<template>
  <div class="storyboard-detail">
    <!-- 导航栏 -->
    <div class="storyboard-header">
      <div class="storyboard-header-left">
        <img src="@/assets/images/back-icon.png" class="back-button" @click="goBack" alt="返回" />
        <span class="episode-seq">第{{ currentEpisode?.seqNo || 1 }}集</span>
      </div>

      <div class="storyboard-progress">
        <div class="progress-item" :class="{ 'active': storyboardActiveTab === 'storyboards' }"
          @click="switchToTab('storyboards')">
          <div class="progress-circle">1</div>
          <div class="progress-text">确定分镜</div>
        </div>
        <div class="progress-line"></div>
        <div class="progress-item" :class="{ 'active': storyboardActiveTab === 'gallery' }"
          @click="switchToTab('gallery')">
          <div class="progress-circle">2</div>
          <div class="progress-text">图集生成</div>
        </div>
        <div class="progress-line"></div>
        <div class="progress-item" :class="{ 'active': storyboardActiveTab === 'video' }" @click="switchToTab('video')">
          <div class="progress-circle">3</div>
          <div class="progress-text">素材生成</div>
        </div>
      </div>

      <div class="storyboard-header-right">
        <!-- 导航按钮 -->
        <div class="header-nav-buttons">
          <el-button color="#1c1d29" v-if="storyboardActiveTab === 'storyboards'" @click="handleNextStep">
            下一步，生成分镜图集
          </el-button>

          <div class="button-group" v-if="storyboardActiveTab === 'gallery'">
            <el-button @click="switchToTab('storyboards')">
              返回分镜编辑
            </el-button>

            <!-- <el-button 
                color="#1c1d29" 
                @click="switchToTab('video')"
              >
                下一步，视频生成
                <el-icon class="ml-1"><ArrowRight /></el-icon>
              </el-button> -->
            <el-button color="#1c1d29" @click="exportImage" :loading="exportLoading">
              导出分镜图
            </el-button>
          </div>

          <div class="button-group" v-if="storyboardActiveTab === 'video'">
            <el-button color="#1c1d29" @click="openExportDialog">
              导出素材
            </el-button>
          </div>
        </div>
      </div>
    </div>

    <!-- 内容区 -->
    <div class="storyboard-content">
      <!-- 左侧剧本区域 -->
      <div class="script-area" v-show="storyboardActiveTab === 'storyboards'">
        <div class="script-header">
          <div class="script-title">分集剧本</div>
          <el-button 
            color="#1c1d29" 
            @click="handleEditEpisode"
            class="edit-episode-btn"
          >
            编辑剧集
          </el-button>
        </div>
        <div class="script-content custom-scrollbar" v-if="scriptContent" v-html="formattedScriptContent"></div>
        <div class="script-loading" v-else-if="scriptLoading">
          <el-icon class="is-loading">
            <Loading />
          </el-icon>
          <span>加载剧本中...</span>
        </div>
        <div class="script-empty" v-else>暂无剧本内容</div>
      </div>

      <!-- 右侧分镜列表 -->
      <div class="storyboard-list-area" v-show="storyboardActiveTab === 'storyboards'">
        <div class="storyboard-list-header">
          <div class="storyboard-list-title">分镜进度 {{storyboardItems.filter(item => item.status).length}}/{{
            storyboardItems.length }}</div>
          <el-button color="#fff" style="border: 1px solid rgba(31, 35, 41, 0.08)" @click="handleAddStoryboardItem">
            添加分镜
          </el-button>
        </div>

        <!-- 加载中状态 -->
        <div class="script-loading" v-if="storyboardLoading">
          <el-icon class="is-loading">
            <Loading />
          </el-icon>
          <span>加载分镜中...</span>
        </div>

        <!-- 分镜列表 -->
        <div v-if="!storyboardLoading && storyboardItems.length > 0" class="storyboard-cards">
          <div v-for="(item, index) in storyboardItems" :key="index" class="storyboard-card">
            <div class="storyboard-card-header">
              <div class="storyboard-card-title">
                {{ item.sbId ? `分镜${item.sbNo}` : '补充分镜' }}
                <span v-if="item.status === 0" class="status-tag status-pending">未确认</span>
                <span v-else class="status-tag status-confirmed">已确认</span>
              </div>
              <el-button class="delete-button" @click="handleDeleteStoryboardItem(index)" link>
                <el-icon>
                  <Delete />
                </el-icon>
              </el-button>
            </div>

            <div class="storyboard-card-content">
              <div class="form-item">
                <div class="form-label">镜头描述</div>
                <el-input v-model="item.sbDesc" type="textarea" :rows="2" placeholder="请输入镜头描述"
                  @change="handleItemChange(item, index)" />
              </div>
              <div class="form-item">
                <div class="form-label">选择模型</div>
                <el-select v-model="item.modelProvider" :suffix-icon="CaretBottom" placeholder="选择模型" @change="handleItemChange(item, index)" class="generate-mode-select">
                  <el-option label="即梦4" value="JIMENG_4" />
                  <el-option label="图片V2" value="SEED" />
                  <el-option label="图片V1" value="MJ" v-if="!item.actorVOList || item.actorVOList.length < 2" />
                  <el-option label="nano banana" value="GEMINI" />
                </el-select>
              </div>
              <div class="form-item" v-if="item.status !== 0">
                <div class="form-label">提示词</div>
                <el-input v-model="item.imagePrompt" type="textarea" :rows="2" placeholder="请输入提示词"
                  @change="handleItemChange(item, index)" />
              </div>

              <div class="form-grid">
                <div class="form-column">
                  <div class="form-label">角色选择</div>
                  <div class="actor-selection">
                    <div class="actor-selection-row">
                      <el-button color="#fff"
                        style="border: 1px solid rgba(31, 35, 41, 0.08);font-weight: 400;color:#1F2329"
                        @click="handleSelectActor(item, index)">
                        选择角色
                      </el-button>
                    </div>
                    <div class="actor-preview-row" v-if="item.actorVOList && item.actorVOList.length > 0">
                      <div class="actor-images-grid">
                        <div v-for="(actor, actorIndex) in item.actorVOList" :key="actorIndex" class="preview-image-wrapper">
                          <img v-if="actor.actorImageUrl" :src="actor.actorImageUrl" class="actor-preview-image" alt="角色预览" />
                          <div class="preview-delete-btn" @click.stop="handleRemoveActor(item, index, actorIndex)">
                            <el-icon><Close /></el-icon>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>

                <div class="form-column">
                  <div class="form-label">场景选择</div>
                  <div class="scene-actions">
                    <div class="scene-actions-content">
                      <div class="scene-buttons">
                        <el-button color="#fff"
                          style="border: 1px solid rgba(31, 35, 41, 0.08);font-weight: 400;color:#1F2329"
                          @click="handleSelectScene(item, index)">
                          切换场景
                        </el-button>
                        <el-button color="#fff"
                          style="border: 1px solid rgba(31, 35, 41, 0.08);font-weight: 400;color:#1F2329"
                          @click="handleCreateScene(item, index)">
                          创建场景
                        </el-button>
                      </div>
                    </div>
                    <div class="preview-scene-wrapper">
                      <div class="current-scene-preview" v-if="item.sceneUrl">
                        <div class="preview-image-wrapper">
                          <el-image :src="item.sceneUrl" class="current-scene-image"
                            alt="当前场景" />
                          <div class="preview-delete-btn" @click.stop="handleRemoveScene(item, index)">
                            <el-icon><Close /></el-icon>
                          </div>
                        </div>
                      </div>
                      <div class="current-scene-text" v-if="item.sceneDesc">
                        <div class="current-scene-text-tip">场景描述</div>
                        <div class="current-scene-text-desc">{{ item.sceneDesc }}</div>
                      </div>
                    </div>
                  </div>
                </div>
              </div>

              <div class="form-actions">
                <el-button color="#1c1d29" @click="handleSaveStoryboardItem(item, index)">
                  {{ item.status === 0 ? '确认' : '修改' }}
                </el-button>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 图集区域 - 内联显示替代弹窗 -->
      <div class="gallery-area" v-show="storyboardActiveTab === 'gallery'">
        <template v-if="currentEpisode">
          <div class="gallery-container">
            <!-- 左侧面板 -->

            <div class="gallery-right-panel">
              <div class="right-panel-header">
                <div class="panel-title">分镜{{ currentStoryboardIndex + 1 }}</div>
                <el-select v-if="currentStoryboard" v-model="currentStoryboard.modelProvider" style="width: 225px;" :suffix-icon="CaretBottom" placeholder="选择模型" @change="handleItemChange(currentStoryboard, currentStoryboardIndex)">
                  <el-option label="即梦4" value="JIMENG_4" />
                  <el-option label="图片V2" value="SEED" />
                  <el-option label="图片V1" value="MJ" v-if="currentStoryboard && (!currentStoryboard?.actorVOList || currentStoryboard?.actorVOList.length < 2)"/>
                  <el-option label="nano banana" value="GEMINI" />
                </el-select>
              </div>

              <div class="right-panel-content" v-if="currentStoryboard">
                <div style="flex:1">
                  <div class="form-label">
                    <div class="form-label-item" @click="labelSelcted = 0" :class="{'label-selected': labelSelcted === 0}">镜头描述</div>
                    <div class="form-label-item" @click="labelSelcted = 1" :class="{'label-selected': labelSelcted === 1}" v-if="currentStoryboard.status !== 0">提示词</div>
                  </div>
                  <el-input v-show="labelSelcted === 0" v-model="currentStoryboard.sbDesc" type="textarea" :rows="7" placeholder="请输入镜头描述"
                    @change="handleItemChange(item, index)" />
                  <el-input v-show="labelSelcted === 1" v-model="currentStoryboard.imagePrompt" type="textarea" :rows="7" placeholder="请输入提示词"
                    @change="handleItemChange(item, index)" />
                </div>
                

                <div class="form-column">
                    <div class="form-label">角色选择</div>
                    <div class="actor-selection">
                      <div class="actor-selection-row">
                        <el-button color="#fff"
                          style="border: 1px solid rgba(31, 35, 41, 0.08);font-weight: 400;color:#1F2329"
                          @click="handleSelectActor(currentStoryboard, storyboardItems.findIndex(item => item.sbId === currentStoryboard.sbId))">
                          选择角色
                        </el-button>
                      </div>
                      <div class="actor-preview-row" v-if="currentStoryboard?.actorVOList && currentStoryboard?.actorVOList.length > 0">
                        <div class="actor-images-grid">
                          <div v-for="(actor, actorIndex) in currentStoryboard?.actorVOList" :key="actorIndex" class="preview-image-wrapper">
                            <img v-if="actor.actorImageUrl" :src="actor.actorImageUrl" class="actor-preview-image" alt="角色预览" />
                            <div class="preview-delete-btn" @click.stop="handleRemoveActor(currentStoryboard, storyboardItems.findIndex(item => item.sbId === currentStoryboard.sbId), actorIndex)">
                              <el-icon><Close /></el-icon>
                            </div>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>

                  <div class="form-column" style="flex:1">
                    <div class="form-label">场景选择</div>
                    <div class="scene-actions">
                      <div class="scene-actions-content">
                        <div class="scene-buttons">
                          <el-button color="#fff"
                            style="border: 1px solid rgba(31, 35, 41, 0.08);font-weight: 400;color:#1F2329"
                            @click="handleSelectScene(currentStoryboard, storyboardItems.findIndex(item => item.sbId === currentStoryboard.sbId))">
                            切换场景
                          </el-button>
                          <el-button color="#fff"
                            style="border: 1px solid rgba(31, 35, 41, 0.08);font-weight: 400;color:#1F2329"
                            @click="handleCreateScene(currentStoryboard, index)">
                            创建场景
                          </el-button>
                        </div>
                      </div>
                      <div class="preview-scene-wrapper">
                        <div class="current-scene-preview" v-if="currentStoryboard.sceneUrl">
                          <div class="preview-image-wrapper">
                            <el-image :src="currentStoryboard.sceneUrl" class="current-scene-image"
                              alt="当前场景" />
                            <div class="preview-delete-btn" @click.stop="handleRemoveScene(currentStoryboard, storyboardItems.findIndex(item => item.sbId === currentStoryboard.sbId))">
                              <el-icon><Close /></el-icon>
                            </div>
                          </div>
                        </div>
                        <div class="current-scene-text" v-if="currentStoryboard.sceneDesc">
                          <div class="current-scene-text-tip">场景描述</div>
                          <div class="current-scene-text-desc">{{ currentStoryboard.sceneDesc }}</div>
                        </div>
                      </div>
                    </div>
                  </div>
              </div>

              <div class="right-panel-button"> 
                <el-button color="#1c1d29" @click="handleSaveStoryboardItem(currentStoryboard, currentStoryboardIndex, true)">
                  重新生成
                </el-button>
              </div>


              <!-- 图集列表 -->
              <div class="gallery-list">
                <div class="gallery-list-title">增强图片生成</div>
                <div v-if="galleryImages.length > 0 || isImageProcessing" class="gallery-grid">
                  <!-- 处理中的加载项 -->
                  <div v-if="isImageProcessing" class="gallery-item loading-item" style="min-height: 350px;">
                    <div class="loading-content">
                      <el-icon class="loading-icon is-loading">
                        <Loading />
                      </el-icon>
                      <span>处理中...</span>
                    </div>
                  </div>

                  <!-- 图片列表 -->
                  <div v-for="(image, index) in galleryImages.filter(item => item.imageStage === 'VARY')" :key="index" class="gallery-item"
                    :class="{ 'gallery-item-active': selectedImageUrl && selectedImageUrl === image.url }" @click="handleSelectImage(image)">
                    <!-- <ImageHoverZoom :imageSrc="image.url" :zoomFactor="2">
                      <el-image fit="cover" :initial-index="index" :src="image.url" class="gallery-thumbnail" />
                    </ImageHoverZoom> -->
                    <template v-if="image?.dataStatus !== 3">
                      <el-image fit="cover" :initial-index="index" :src="image.url" class="gallery-thumbnail" />

                      <!-- 图片操作菜单 -->
                      <div class="image-actions">
                        <div class="opt-wrapper" @click.stop="handleImageAction('enhance', image)" v-if="!['seed', 'gemini', 'jimeng_4'].includes(image?.businessSupport)">
                          <svg-icon class="opt-icon" icon-class="zengqiang" />
                          <div class="opt-text">增强</div>
                        </div>
                        <div class="opt-wrapper" @click.stop="handleImageAction('refine', image)" v-if="!['seed', 'gemini', 'jimeng_4'].includes(image?.businessSupport)">
                          <svg-icon class="opt-icon" icon-class="jingxi" />
                          <div class="opt-text">精细</div>
                        </div>
                        <div class="opt-wrapper" @click.stop="handleImageEdit(image)">
                          <svg-icon class="opt-icon" icon-class="zhonghui" />
                          <div class="opt-text">编辑</div>
                        </div>
                      </div>
                    </template>
                    <template v-else>
                      <div class="image-fail-wrapper">
                        <div>生成失败</div>
                        <el-tooltip
                          popper-style="width: 240px"
                          placement="top" 
                          :show-after="200"
                          :hide-after="0">
                          <template #content>{{ image.failReason }}</template>
                          <div class="image-fail-text">
                            查看原因
                          </div>
                        </el-tooltip>
                      </div>
                    </template>
                  </div>
                </div>
                <div v-else-if="refreshingImages" class="empty-gallery-container">
                  <div class="loading-content">
                    <el-icon class="loading-icon is-loading">
                      <Loading />
                    </el-icon>
                    <span class="loading-text">加载中...</span>
                  </div>
                </div>
                <div v-else class="empty-gallery-container">
                  <el-empty description="暂无分镜图" :image-size="120">

                  </el-empty>
                </div>
              </div>
              <div class="gallery-list">
                <div class="gallery-list-title mt-16px">标准图片生成</div>
                <div v-if="galleryImages.length > 0 || isImageProcessing" class="gallery-grid">
                  <!-- 图片列表 -->
                  <div v-for="(image, index) in galleryImages.filter(item => item.imageStage !== 'VARY')" :key="index" class="gallery-item"
                    :class="{ 'gallery-item-active': selectedImageUrl && selectedImageUrl === image.url }" @click="handleSelectImage(image)">
                    <!-- <ImageHoverZoom :imageSrc="image.url" :zoomFactor="2">
                      <el-image fit="cover" :initial-index="index" :src="image.url" class="gallery-thumbnail" />
                    </ImageHoverZoom> -->
                    <template v-if="image?.dataStatus !== 3">
                      <el-image fit="cover" :initial-index="index" :src="image.url" class="gallery-thumbnail" />

                      <!-- 图片操作菜单 -->
                      <div class="image-actions">
                        <div class="opt-wrapper" @click.stop="handleImageAction('enhance', image)" v-if="!['seed', 'gemini','jimeng_4'].includes(image?.businessSupport)">
                          <svg-icon class="opt-icon" icon-class="zengqiang" />
                          <div class="opt-text">增强</div>
                        </div>
                        <div class="opt-wrapper" @click.stop="handleImageAction('refine', image)" v-if="!['seed', 'gemini', 'jimeng_4'].includes(image?.businessSupport)">
                          <svg-icon class="opt-icon" icon-class="jingxi" />
                          <div class="opt-text">精细</div>
                        </div>
                        <div class="opt-wrapper" @click.stop="handleImageEdit(image)">
                          <svg-icon class="opt-icon" icon-class="zhonghui" />
                          <div class="opt-text">编辑</div>
                        </div>
                      </div>
                    </template>
                    <template v-else>
                      <div class="image-fail-wrapper">
                        <div>生成失败</div>
                        <el-tooltip
                          popper-style="width: 240px"
                          placement="top" 
                          :show-after="200"
                          :hide-after="0">
                          <template #content>{{ image.failReason }}</template>
                          <div class="image-fail-text">
                            查看原因
                          </div>
                        </el-tooltip>
                      </div>
                    </template>
                  </div>
                </div>
                <div v-else-if="refreshingImages" class="empty-gallery-container">
                  <div class="loading-content">
                    <el-icon class="loading-icon is-loading">
                      <Loading />
                    </el-icon>
                    <span class="loading-text">加载中...</span>
                  </div>
                </div>
                <div v-else class="empty-gallery-container">
                  <el-empty description="暂无分镜图" :image-size="120">

                  </el-empty>
                </div>
              </div>
            </div>
            <!-- 右侧面板 -->
            <div class="gallery-left-panel">
              <!-- 2. 选中图片模块 -->
              <div class="left-panel-card">
                <!-- 1. 标题及操作模块 -->
                <div class="left-panel-header">
                  <div class="storyboard-counter">
                    <span class="mr-2">分镜</span>
                    <el-select v-model="currentStoryboardIndex" :suffix-icon="CaretBottom" @change="changeStoryboardIndex" placeholder="请选择"
                      style="width: 60px" size="small">
                      <el-option v-for="item in Array(storyboardItems.length).fill().map((_, i) => i)" :key="item"
                        :label="item + 1" :value="item" />
                    </el-select>
                    <span class="ml-2">/ {{ storyboardItems.length }}</span>
                  </div>
                  <div class="navigation-buttons">
                    <div class="opt-button">
                      <img src="@/assets/images/back-icon.png" @click="handlePrevStoryboard" class="opt-back-button" />
                    </div>
                    <div class="opt-button">
                      <img src="@/assets/images/back-icon.png" @click="handleNextStoryboard"
                        class="opt-forward-button" />
                    </div>
                  </div>
                </div>
                <div class="card-title">
                  <div>当前选中</div>
                  <div class="upload-btn-wrapper" @click="handleUploadClick">
                    <img src="@/assets/images/download.png" class="upload-btn-icon" />
                    <div class="upload-btn-text">本地上传</div>
                  </div>
                </div>
                <div v-if="!!selectedImage.url.trim()" class="selected-image-container rounded-lg" @click="previewVisible = true;previewImageUrl = selectedImage.url;">
                  <img :src="selectedImage.url" class="selected-image" />
                </div>
                <div v-else class="selected-image-placeholder">
                  <span>暂无</span>
                </div>

                <div class="mt-4" v-if="selectedImage && (selectedImage.resKey || selectedImage.url)">
                  <el-button color="#1c1d29" @click="handleSetAsStoryboardImage"
                    :disabled="!(selectedImage && (selectedImage.resKey || selectedImage.url))" style="width: 100%;">
                    保存图片
                  </el-button>
                </div>

                <!-- 隐藏的文件上传输入 -->
                <input id="fileInput" ref="fileInputRef" type="file" accept="image/*" style="display: none"
                  @change="handleFileChange" />
              </div>
              <div class="left-panel-card" v-show="selectedStoryboardImages.map(item => item.sbNo).includes(currentStoryboard?.sbNo)">
                <div class="card-title" style="font-weight: bold;">转视频</div>
                <!-- 视频时长选择 -->
                <div class="video-option-wrapper">
                  <div class="video-option-title">视频时长</div>
                  <div v-for="option in selectedModel === 'sora2' ? soraDurationOptions : selectedModel === 'sora2-duomi' ? soraV2DurationOptions : durationOptions" :key="option.value"
                    @click="selectedDuration = option.value" :class="[
                      selectedDuration === option.value
                        ? 'video-button video-button-active'
                        : 'video-button'
                    ]">
                    {{ option.label }}
                  </div>
                </div>

                <!-- 视频模型选择 -->
                <div class="video-option-wrapper">
                  <div class="video-option-title">视频模型</div>
            <el-select v-model="selectedModel" :suffix-icon="CaretBottom" placeholder="请选择" class="w-full">
                    <el-option v-for="model in modelOptions" :key="model.value" :label="model.label"
                      :value="model.value" />
                  </el-select>
                </div>

                <!-- 视频提示词输入 -->
                <div class="mb-8" v-if="currentStoryboard">
                  <div class="text-gray-600 mb-3" style="color:#64687A;font-size:14px">视频提示词</div>
                  <textarea v-model="currentStoryboard.videoPrompt"
                    style="color:#1C1D29;font-size:14px;padding:8px 12px"
                    class="w-full h-40 border border-gray-200 rounded-lg focus:outline-none focus:ring-1 focus:ring-blue-500 transition-all"
                    placeholder="请输入视频提示词..."></textarea>
                </div>

                <!-- 生成视频按钮 -->
                <el-button color="#1c1d29" style="height: 36px;" @click="handleGenerateVideo" :loading="loadingVideoStep2"
                  class="w-full"
                  :disabled="!currentStoryboard || !selectedStoryboardImages.find(img => img.sbNo === (currentStoryboard.sbNo || currentStoryboardIndex + 1))">
                  生成视频
                </el-button>
              </div>

              <!-- 3. 已选中画面模块 -->
              <div class="left-panel-card">
                <div class="card-title">已选中画面</div>
                <div class="selected-images-container bg-gray-50 p-4 rounded-lg">
                  <div v-if="selectedStoryboardImages.length > 0" class="selected-storyboard-images-grid">
                    <div v-for="(image, index) in selectedStoryboardImages" :key="index"
                      class="selected-storyboard-image"
                      :class="{ 'current-storyboard-image': image.storyboardIndex === currentStoryboardIndex }">
                      <img :src="image.url" class="w-full object-cover rounded" />
                      <div class="text-xs text-center mt-1 truncate">分镜{{ image.sbNo }}</div>
                    </div>
                  </div>
                  <div v-else class="text-gray-400 text-center py-4">
                    暂无已选中画面
                  </div>
                </div>
              </div>
            </div>
          </div>
        </template>
      </div>

      <!-- 视频区域 -->
      <div class="video-area" v-show="storyboardActiveTab === 'video'">
        <!-- start -->
        <div class="storyboard-area">
          <div class="storyboard-area-title">
            <div class="storyboard-area-title-text">分镜</div>
            <div class="storyboard-area-title-count">共计{{ storyboardItems.length }}</div>
          </div>
          <div class="storyboard-area-content-item" :class="{'active': curStoryBoard?.sbId === storyboardItem.sbId}" v-for="(storyboardItem, index) in storyboardItems" :key="storyboardItem.id" @click="selectStoryboardVideo(storyboardItem)">
            <img class="storyboard-area-content-item-img" v-if="storyboardItem.imageUrl" :src="storyboardItem.imageUrl" />
            <div class="storyboard-area-content-item-img" style="padding-top: 20px;" v-else>暂无</div>
            <div class="storyboard-area-content-item-footer">{{ index+1 }}/{{ storyboardItems.length }}</div>
          </div>
        </div>
        <div class="video-display-area">
          <div class="video-display-area-main">
            <VideoPlayer
              ref="playerRef"
              :src="curVideoUrl"
              :autoplay="false"
              :img="curStoryBoard?.imageUrl"
            />
          </div>
          <div class="video-display-area-list">
            <!-- 处理中的加载项 -->
            <div v-if="storyboardVideoLoading" class="gallery-item loading-item" style="width: 72px;height: 128px;">
              <div class="loading-content">
                <el-icon class="loading-icon is-loading">
                  <Loading />
                </el-icon>
              </div>
            </div>
            <div style="position:relative;flex-shrink: 0;" v-for="(video, index) in storyboardVideoList.filter(item => item.videoStatus !== 3 && item.videoStatus !== 0 && item.videoStatus !== 5)" :key="index">
              <template v-if="video.videoStatus !== -1">
                <div class="selected-selected-indicator" v-if="video && video.videoUrl && video.videoUrl.includes(curStoryBoard?.videoUrl?.split('?')[0])">
                  <el-icon class="check-icon"><Check /></el-icon>
                </div>
                <img class="video-display-area-img" :class="{'active': video && video.videoUrl && video.videoUrl.includes(curStoryBoard?.videoUrl?.split('?')[0])}" :src="video.coverUrl" @click="selectVideo(video)" />
              </template>
              <div v-else class="video-display-area-error-img">
                <div>生成失败</div>
                <el-tooltip
                  popper-style="width: 240px"
                  placement="top" 
                  :show-after="200"
                  :hide-after="0">
                  <template #content>{{ video.errorMessage }} </template>
                  <div class="video-display-area-error-text">
                    查看原因
                  </div>
                </el-tooltip>
              </div>
            </div>
          </div>
        </div>
        <div class="video-info-area">
          <div class="video-type-switch mb-4">
            <el-radio-group v-model="videoInfoType" size="large" text-color="#1c1d29" fill="#fff">
              <el-radio-button label="generate">视频生成</el-radio-button>
              <el-radio-button label="detail">镜头详情</el-radio-button>
            </el-radio-group>
          </div>
          <template v-if="videoInfoType === 'detail'">
            <div class="video-info-title">镜头描述</div>
            <div class="video-info-text" style="margin-bottom: 16px;">{{ curStoryBoard?.sbDesc }}</div>
            <div class="video-info-title" v-if="curStoryBoard?.actorName">角色选择</div>
            <div class="video-info-text" v-if="curStoryBoard?.actorName">{{ curStoryBoard?.actorName }}</div>
            <img class="video-info-img" v-if="curStoryBoard?.actorName" :src="curStoryBoard?.actorImageUrl" />
            <div class="video-info-title" v-if="curStoryBoard?.sceneDesc">场景选择</div>
            <div class="video-info-title" v-if="curStoryBoard?.sceneDesc">{{ curStoryBoard?.sceneDesc }}</div>
            <img class="video-info-img" style="margin-bottom: 16px;" :src="curStoryBoard?.sceneUrl" />
            <div class="video-info-title">分镜图片</div>
            <img class="video-info-img" :src="curStoryBoard?.imageUrl" />
          </template>
          <template v-if="videoInfoType === 'generate'">
            <div class="video-option-wrapper">
              <div class="video-option-title">视频时长</div>
              <div v-for="option in videoModel === 'sora2' ? soraDurationOptions : videoModel === 'sora2-duomi' ? soraV2DurationOptions : durationOptions" :key="option.value"
                @click="videoDuration = option.value" :class="[
                  videoDuration === option.value
                    ? 'video-button video-button-active'
                    : 'video-button'
                ]">
                {{ option.label }}
              </div>
            </div>

            <!-- 视频模型选择 -->
            <div class="video-option-wrapper">
              <div class="video-option-title">视频模型</div>
            <el-select v-model="videoModel" :suffix-icon="CaretBottom" placeholder="请选择" class="w-full">
                <el-option v-for="model in modelOptions" :key="model.value" :label="model.label"
                  :value="model.value" />
              </el-select>
            </div>

            <!-- 视频提示词输入 -->
            <div class="mb-8" v-if="curStoryBoard">
              <div class="text-gray-600 mb-3" style="color:#64687A;font-size:14px">视频提示词</div>
              <textarea v-model="curStoryBoard.videoPrompt"
                style="color:#1C1D29;font-size:14px;padding:8px 12px"
                class="w-full h-40 border border-gray-200 rounded-lg focus:outline-none focus:ring-1 focus:ring-blue-500 transition-all"
                placeholder="请输入视频提示词..."></textarea>
            </div>

            <!-- 生成视频按钮 -->
            <el-button color="#1c1d29" style="height: 36px;" @click="reHandleGenerateVideo" :loading="loadingVideoStep3" :disabled="storyboardVideoLoading"
              class="w-full">
              重新生成
            </el-button>
          </template>
        </div>
      </div>
    </div>

    

    <!-- 场景选择弹窗 -->
    <el-dialog v-model="sceneDialogVisible" title="切换场景" width="500px" destroy-on-close>
      <el-form ref="sceneFormRef" :model="sceneForm" :rules="sceneRules" label-width="80px">
        <el-form-item label="选择场景" prop="sceneId" required>
          <el-select v-model="sceneForm.sceneId" :suffix-icon="CaretBottom" placeholder="请选择场景" style="width: 100%" filterable
            @change="handleSceneChange">
            <el-option v-for="scene in scenes" :key="scene.id" :label="scene.sceneName" :value="scene.sceneId" />
          </el-select>
        </el-form-item>
        <el-form-item label="场景预览" prop="sceneDesc" v-if="sceneForm.sceneId">
          <el-image :src="scenes.find(item => item.sceneId === sceneForm.sceneId)?.sceneImageUrl"
            class="scene-preview-image" />
        </el-form-item>
      </el-form>

      <template #footer>
        <div class="dialog-footer">
          <el-button @click="sceneDialogVisible = false">取消</el-button>
          <el-button color="#1c1d29" @click="handleConfirmSelectScene">确定</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 删除图集弹窗，内容已移至内联显示区域 -->

    <!-- 场景创建弹窗 -->
    <el-dialog v-model="createSceneDialogVisible" title="创建场景" width="680px" :close-on-click-modal="false"
      destroy-on-close custom-class="scene-dialog">
      <template #header>
        <div class="dialog-title">创建场景</div>
      </template>
      <el-form ref="createSceneFormRef" :model="createSceneForm" :rules="createSceneRules" label-position="top">
        <el-form-item>
          <template #label>
            <span class="form-label">场景名称<span class="required-mark">*</span></span>
          </template>
          <el-input v-model="createSceneForm.sceneName" placeholder="请输入场景名称" maxlength="50" show-word-limit />
        </el-form-item>

        <el-form-item>
          <template #label>
            <span class="form-label">场景描述<span class="required-mark">*</span></span>
          </template>
          <el-input v-model="createSceneForm.sceneDesc" type="textarea" :rows="3" placeholder="请输入场景描述"
            show-word-limit />
        </el-form-item>

        <el-form-item>
          <template #label>
            <span class="form-label">所属剧集<span class="required-mark">*</span></span>
          </template>
          <el-select v-model="createSceneForm.seqNo" :suffix-icon="CaretBottom" placeholder="请选择所属剧集" class="w-full" :loading="loadingSeries">
            <el-option v-for="series in seriesList" :key="series.seqNo" :label="`第${series.seqNo}集`"
              :value="series.seqNo" />
          </el-select>
        </el-form-item>

        <el-form-item>
          <template #label>
            <span class="form-label">场景图<span class="required-mark">*</span></span>
          </template>

          <!-- 上传方式切换 -->
          <div class="upload-type-switch mb-4">
            <el-radio-group v-model="uploadType" size="large" text-color="#1c1d29" fill="#fff">
              <el-radio-button label="local">本地上传</el-radio-button>
              <el-radio-button label="ai">AI生成</el-radio-button>
            </el-radio-group>
          </div>

          <!-- 本地上传 -->
          <div v-if="uploadType === 'local'" class="image-upload-container">
            <PicUpload @start="beforeImageUpload" @finish="handleCreateSceneImageUpload"
              :defaultUrl="createSceneForm.sceneImageUrl" />
          </div>
          <!-- AI生成 -->
          <div v-else class="ai-tip">
            点击下方按钮将根据场景名称和描述自动生成，确定之后需回到列表进行场景确认
          </div>
        </el-form-item>
      </el-form>

      <template #footer>
        <span class="dialog-footer">
          <el-button @click="createSceneDialogVisible = false">取消</el-button>
          <el-button color="#1c1d29" @click="handleSaveCreateScene" :loading="saveCreateSceneLoading">保存</el-button>
        </span>
      </template>
    </el-dialog>

    <!-- 角色选择弹窗 -->
    <el-dialog v-model="actorDialogVisible" title="选择角色及视图" width="800px" destroy-on-close class="actor-select-dialog" :show-close="false">
      <template #header="{ close, titleId, titleClass }">
        <div style="width: 756px;">
          <div class="actor-select-header-close">
            <div>选择角色和视图</div>
            <el-icon :size="16" @click="close"><Close /></el-icon>
          </div>
          <!-- 第一行：标题和新增按钮 -->
          <div class="actor-select-header">
            <div class="header-title">请选择1~5个角色</div>
            <el-button color="#1c1d29" @click="addActorForm" :disabled="actorForms.length >= 5">
              新增角色
            </el-button>
          </div>
        </div>
      </template>
      <div class="actor-select-content">
        <!-- 角色表单列表 -->
        <div v-for="(formItem, index) in actorForms" :key="index" class="actor-form-item">
          <!-- 选择角色 -->
          <div class="form-item">
            <div class="form-label">
              <div>选择角色<span class="required-mark">*</span></div>
              <el-button class="delete-button" v-if="actorForms.length >= 2" @click="removeActorForm(index)" link>
                <el-icon>
                  <Delete />
                </el-icon>
              </el-button>
            </div>
            <el-select
              :suffix-icon="CaretBottom"
              v-model="formItem.actorId"
              placeholder="请选择角色"
              filterable
              style="width: 100%"
              @change="handleActorSelectChange(index, $event)"
            >
              <el-option v-for="role in roles" :key="role.id" :label="role.actorName" :value="role.actorId" />
            </el-select>
          </div>

          <!-- 选择角色视图 -->
          <div class="form-item">
            <div class="form-label"><div>选择角色视图<span class="required-mark">*</span></div></div>
            <el-select
              :suffix-icon="CaretBottom"
              v-model="formItem.perspective"
              placeholder="请选择角色视图"
              filterable
              style="width: 100%"
              @change="handlePerspectiveChange(index, $event)"
            >
              <el-option v-for="view in actorViews" :key="view.value" :label="view.label" :value="view.value" />
            </el-select>
          </div>

          <!-- 图片预览 -->
          <div v-if="formItem.actorId && formItem.perspective" class="actor-images-preview">
            <div class="form-label">图片预览</div>
            <div class="actor-images-grid">
              <div class="actor-image-item" v-if="formItem.perspective === 'WHOLE_BODY_FRONT'">
                <img v-if="getSelectedActor(formItem.actorId)?.wholeBodyFrontImageUrl" :src="getSelectedActor(formItem.actorId).wholeBodyFrontImageUrl"
                  class="actor-view-image" alt="主图" />
                <div v-else class="actor-view-placeholder">暂无主图</div>
              </div>

              <div class="actor-image-item" v-if="formItem.perspective === 'WHOLE_BODY_SIDE'">
                <img v-if="getSelectedActor(formItem.actorId)?.wholeBodySideImageUrl" :src="getSelectedActor(formItem.actorId).wholeBodySideImageUrl"
                  class="actor-view-image" alt="侧图" />
                <div v-else class="actor-view-placeholder">暂无侧图</div>
              </div>

              <div class="actor-image-item" v-if="formItem.perspective === 'WHOLE_BODY_BACK'">
                <img v-if="getSelectedActor(formItem.actorId)?.wholeBodyBackImageUrl" :src="getSelectedActor(formItem.actorId).wholeBodyBackImageUrl"
                  class="actor-view-image" alt="背图" />
                <div v-else class="actor-view-placeholder">暂无背图</div>
              </div>

              <div class="actor-image-item" v-if="formItem.perspective === 'HALF_BODY'">
                <img v-if="getSelectedActor(formItem.actorId)?.halfBodyImageUrl" :src="getSelectedActor(formItem.actorId).halfBodyImageUrl"
                  class="actor-view-image" alt="半身图" />
                <div v-else class="actor-view-placeholder">暂无半身图</div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <template #footer>
        <span class="dialog-footer">
          <el-button @click="actorDialogVisible = false">取消</el-button>
          <el-button color="#1c1d29" @click="handleConfirmSelectActor">
            确定
          </el-button>
        </span>
      </template>
    </el-dialog>

    <!-- 导出素材弹窗 -->
    <el-dialog v-model="exportDialogVisible" title="导出素材" width="800px" destroy-on-close class="export-dialog">
      <div class="export-dialog-content">
            <div class="export-storyboard-grid">
      <div 
        v-for="(item, index) in confirmedVideo" 
        :key="index" 
        class="storyboard-area-content-item"
        :class="{ 'selected-export-item': selectedExportItems.includes(item.sbId) }"
        @click="toggleExportSelection(item)"
      >
        <img 
          :src="getStoryboardImageUrl(item)" 
          class="storyboard-area-content-item-img" 
          alt="分镜预览"
        />
        <div class="storyboard-area-content-item-footer">{{ item.sbNo }}/{{ storyboardItems.length }}</div>
        <div v-if="selectedExportItems.includes(item.sbId)" class="selected-export-indicator">
          <el-icon class="check-export-icon"><Check /></el-icon>
        </div>
        <div v-else class="empty-circle"></div>
      </div>
    </div>
      </div>

      <template #footer>
        <div class="export-dialog-footer">
          <div class="left-actions">
            <div @click="handleSelectAllChange" style="cursor: pointer;">
              <div v-if="selectAllExport" class="selected-full-indicator">
                <el-icon class="check-export-icon"><Check /></el-icon>
              </div>
              <div v-else class="empty-full-circle"></div>
            </div>
            <div style="color: #000;font-size: 14px;margin-left: 8px;">全选</div>
          </div>
          <div class="right-actions">
        <el-button @click="exportDialogVisible = false">取消</el-button>
        <el-button color="#1c1d29" @click="exportVideo" :loading="exportLoading" :disabled="selectedExportItems.length === 0">
          确定
        </el-button>
      </div>
        </div>
      </template>
    </el-dialog>

    <!-- 图片预览 -->
    <ImagePreview 
      v-model:visible="previewVisible" 
      :image-url="previewImageUrl" 
    />

    <!-- 图片编辑弹窗 -->
    <ImageEditorModal
      v-model:visible="imageEditorVisible"
      :image-url="editingImageUrl"
      :business-id="editingBusinessId"
      :business-type="editingBusinessType"
      :roles="roles"
      :drama-id="dramaId"
      @close="handleImageEditorClose"
      @save="handleImageEditorSave"
      @generation-completed="handleImageGenerationCompleted"
    />

    <!-- 编辑剧集弹窗 -->
    <el-dialog
      v-model="editEpisodeDialogVisible"
      title="编辑剧集"
      width="500px"
      destroy-on-close
      class="edit-episode-dialog"
    >
      <el-form
        ref="editEpisodeFormRef"
        :model="editEpisodeForm"
        :rules="editEpisodeRules"
        label-width="80px"
        label-position="top"
      >
        <el-form-item label="剧集编号">
          <el-input 
            v-model="editEpisodeForm.seqNo" 
            disabled
            type="number"
          />
        </el-form-item>
        
        <el-form-item label="剧集内容" prop="content">
          <el-input
            v-model="editEpisodeForm.content"
            type="textarea"
            :rows="10"
            placeholder="请输入剧集内容"
          />
        </el-form-item>
      </el-form>
      
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="editEpisodeDialogVisible = false">取消</el-button>
          <el-button 
            color="#1c1d29" 
            @click="handleConfirmEditEpisode" 
            :loading="editEpisodeLoading"
          >
            修改
          </el-button>
        </div>
      </template>
    </el-dialog>

  </div>
</template>

<script setup>
import { ref, computed, reactive, watch, nextTick, onMounted, onUnmounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { ElMessage, ElMessageBox, ElLoading, ElTooltip } from 'element-plus'
import { ElTabs, ElTabPane } from 'element-plus'
import { orderBy } from 'lodash-es'
import { getDramaStoryboard, preInitStoryboard, confirmSaveStoryboard, saveOrUpdateStoryboard, deleteStoryboard, queryStoryboardImageList, queryStoryboardVideoList, generateStoryboardImage, initSeriesList, getDramaSeries, getDramaActor, getDramaScene, createScene, uploadFile, confirmStoryboard, confirmStoryboardImage, confirmStoryboardVideo, exportStoryboardImages, exportStoryboardVideo, reExportStoryboardImagesAgain, getConfirmedStoryboardImages, generateVideo, confirmedVideoList, updateSeries } from '@/api/drama'
import dayjs from 'dayjs'
import request from '@/utils/request'
import PicUpload from '@/components/common/PicUpload.vue'
import VideoPlayer from '@/components/common/VideoPlayer.vue';
import ImagePreview from '@/components/common/ImagePreview.vue'
import ImageEditorModal from '@/components/common/ImageEditorModal.vue'
// import ImageHoverZoom from '@/components/common/ImageHoverZoom.vue'

import { Plus, Edit, Delete, Download, Upload, ArrowLeft,CaretBottom, ArrowRight, Star, ZoomOut, ZoomIn, Check, Refresh, Loading, VideoPlay, VideoCamera, Picture, InfoFilled, Cpu, Close } from '@element-plus/icons-vue'
import { createSceneByAI } from '../../../api/drama'

// 视频转换选项数据
const durationOptions = [
  { value: 5, label: "5 秒" },
  { value: 10, label: "10 秒" }
]

const soraDurationOptions = [
  { value: 4, label: "4 秒" },
  { value: 8, label: "8 秒" },
  { value: 12, label: "12 秒" },
]

const soraV2DurationOptions = [
  { value: 10, label: "10 秒" },
  { value: 15, label: "15 秒" }
]

const actorViews = [
  { value: 'WHOLE_BODY_FRONT', label: '主图' },
  { value: 'WHOLE_BODY_SIDE', label: '侧图' },
  { value: 'WHOLE_BODY_BACK', label: '背图' },
  { value: 'HALF_BODY', label: '半身图' }
]

const modelOptions = [
  { value: "sora2-duomi", label: "分镜增强模型（备用）" },
  { value: "sora2", label: "分镜增强模型 V1" },
  { value: "jimeng3", label: "即梦3.0" }
]

// 响应式状态
const selectedDuration = ref(5)
const videoDuration = ref(5)
const selectedModel = ref("sora2-duomi")
const videoModel = ref("sora2-duomi")
const prompt = ref("")
const curStoryBoard = ref(null)
const curVideoUrl = ref('')
const labelSelcted = ref(0)

const selectVideo = async (video) => {
  curVideoUrl.value = video.videoUrl
  curStoryBoard.value.videoUrl = video.videoUrl
  // 确认视频接口
  await confirmStoryboardVideo({
    sbId: curStoryBoard.value.sbId,
    videoUrl: video.videoUrl,
    resKey: video.resKey
  })
}

const loadingVideoStep3 = ref(false)
const reHandleGenerateVideo = async() => {
  loadingVideoStep3.value = true
  // 构建视频生成参数
  const videoParams = {
    dramaId: dramaId.value,
    sbId: curStoryBoard.value.sbId,
    videoDuration: videoDuration.value,
    videoModelType: videoModel.value,
    prompt: curStoryBoard.value.videoPrompt
  }

  console.log('视频生成参数:', videoParams)

  // 这里可以添加实际的视频生成API调用
  // 示例: await generateVideo(videoParams)
  try {
    await generateVideo(videoParams)
    storyboardVideoLoading.value = true
    setTimeout(() => {
      selectStoryboardVideo(curStoryBoard.value)
    }, 15000);
    ElMessage.success('生成视频成功！')
  } catch (error) {
    console.error('生成视频失败:', error)
    ElMessage.error('生成视频失败，请重试')
  } finally {
    // loadingVideoStep3.value = false
  }
}
const loadingVideoStep2 = ref(false)


// 处理生成视频按钮点击
const handleGenerateVideo = async() => {
  loadingVideoStep2.value = true
  if (!currentStoryboard.value) {
    ElMessage.warning('请先选择分镜')
    return
  }

  const selectedImage = selectedStoryboardImages.value.find(img => img.sbNo === (currentStoryboard.value.sbNo || currentStoryboardIndex.value + 1))
  if (!selectedImage) {
    ElMessage.warning('当前分镜没有确认的图片')
    return
  }

  // 构建视频生成参数
  const videoParams = {
    dramaId: dramaId.value,
    sbId: currentStoryboard.value.sbId,
    videoDuration: selectedDuration.value,
    videoModelType: selectedModel.value,
    prompt: currentStoryboard.value.videoPrompt
  }

  console.log('视频生成参数:', videoParams)

  // 这里可以添加实际的视频生成API调用
  // 示例: await generateVideo(videoParams)
  try {
    await generateVideo(videoParams)
    ElMessage.success('生成视频成功！')
  } catch (error) {
    console.error('生成视频失败:', error)
    ElMessage.error('生成视频失败，请重试')
  } finally {
    loadingVideoStep2.value = false
  }
}

// 生成视频缩略图数组 - 重命名以避免与现有函数冲突
const generateThumbnails = (count, imageUrl) => {
  return Array.from({ length: count }, (_, i) => ({
    id: i,
    imageUrl
  }));
};

const router = useRouter()
const route = useRoute()

// 获取路由参数
const dramaId = ref(route.params.dramaId || '')
const seriesId = ref(route.params.seriesId || '')

// 从URL查询参数获取tab
const tabParam = ref(route.query.tab || '')

// Define emits
const emit = defineEmits(['switch-tab', 'clear-series'])

// 分集列表
const loading = ref(false)
const initSeriesLoading = ref(false)
const episodes = ref([])
const currentEpisode = ref(null)

// 角色和场景数据
const roles = ref([])
const scenes = ref([])
const storyboardVideoList = ref([])
const storyboardVideoLoading = ref(false)

// 分镜标签
const storyboardActiveTab = ref('storyboards')
const storyboardItems = ref([])
const initLoading = ref(false)
const savingStoryboard = ref(false)
const storyboardLoading = ref(true)
const pollingCount = ref(0)
const maxPollingCount = ref(120) // 10分钟，每5秒一次，共120次

// 是否是第一次分镜初始化状态位
const isFirstInitStoryboard = ref(true)

const storyboardItemForm = reactive({
  sbNo: '',
  actors: [],
  sbDesc: '',
  imagePrompt: '',
  videoPrompt: '',
  modelProvider: 'JIMENG_4'
})

const storyboardItemRules = {
  sbNo: [
    { required: true, message: '请输入分镜名称', trigger: 'blur' }
  ],
  actors: [
    { required: true, message: '请添加角色', trigger: 'change' }
  ],
  sbDesc: [
    { required: true, message: '请输入镜头描述', trigger: 'blur' }
  ]
}

// 图集弹窗 - 移除弹窗控制，仅保留相关数据状态
const galleryImages = ref([])
const selectedImageUrl = ref('')
const selectedImagePrompt = ref('')
const currentStoryboardIndex = ref(0)
const generatingImages = ref(false)
const refreshingImages = ref(false)
// 存储所有分镜的图集列表
const storyboardGalleries = ref(new Map())
// 图片处理状态
const isImageProcessing = ref(false)
// 轮询定时器
const imagePollingTimer = ref(null)

// 图片预览弹窗
const previewVisible = ref(false)
const previewImageUrl = ref('')
const previewImageIndex = ref(0)

// 图片编辑弹窗
const imageEditorVisible = ref(false)
const editingImageUrl = ref('')
const editingBusinessType = ref('')
const editingBusinessId = ref('')

// 剧本内容
const scriptContent = ref('')
const scriptLoading = ref(true)

// 编辑剧集弹窗相关
const editEpisodeDialogVisible = ref(false)
const editEpisodeLoading = ref(false)
const editEpisodeFormRef = ref(null)
const currentEditingEpisode = ref(null)

const editEpisodeForm = reactive({
  seqNo: null,
  content: ''
})

const editEpisodeRules = {
  content: [
    { required: true, message: '请输入剧集内容', trigger: 'blur' }
  ]
}

const videoInfoType = ref('generate')

// 格式化剧本内容，处理换行符
const formattedScriptContent = computed(() => {
  if (!scriptContent.value) return ''
  // 将\n替换为<br>实现换行
  return scriptContent.value.replace(/\n/g, '<br>')
})

const selectStoryboardVideo = (storyboardItem) => {
  curStoryBoard.value = storyboardItem
  loadVideoListByStoryboard(storyboardItem.sbId, storyboardItem)
}

// 获取剧本内容
const fetchScriptContent = async () => {
  if (!seriesId.value) return

  try {
    scriptLoading.value = true
    const { data } = await request.post(`/evox-drama/series/detail/${seriesId.value}`)

    if (data && data.content) {
      scriptContent.value = data.content
    } else {
      scriptContent.value = ''
    }
  } catch (error) {
    console.error('获取剧本内容失败:', error)
    ElMessage.error('获取剧本内容失败')
    scriptContent.value = ''
  } finally {
    scriptLoading.value = false
  }
}

// 初始化数据
onMounted(async () => {
  try {
    loading.value = true

    // 根据URL参数设置初始标签
    if (tabParam.value === '1') {
      storyboardActiveTab.value = 'storyboards'
    } else if (tabParam.value === '2') {
      storyboardActiveTab.value = 'gallery'
    } else {
      storyboardActiveTab.value = 'video'
    }

    // 获取角色数据
    const { data: roleData } = await getDramaActor(dramaId.value)
    if (roleData) {
      roles.value = roleData
    }

    // 获取场景数据
    const { data: sceneData } = await getDramaScene(dramaId.value)
    if (sceneData) {
      scenes.value = sceneData
    }

    // 获取剧集数据
    if (seriesId.value) {
      const { data: seriesData } = await getDramaSeries(dramaId.value)
      if (seriesData) {
        episodes.value = seriesData

        // 找到当前剧集
        const episode = episodes.value.find(item => item.seriesId === seriesId.value)
        if (episode) {
          currentEpisode.value = episode

          // 加载分镜数据
          await loadStoryboardData()

          // 加载剧本内容
          fetchScriptContent()

          // 如果是图集标签，加载图集数据
          if (storyboardActiveTab.value === 'gallery') {
            loadGalleryData()
          }
          if (storyboardActiveTab.value === 'video') {
            loadVideoListByStoryboard(curStoryBoard.value.sbId, curStoryBoard.value)
          }
        } else {
          ElMessage.error('未找到指定的剧集数据')
          goBack()
        }
      }
    } else {
      ElMessage.error('缺少必要的剧集参数')
      goBack()
    }
  } catch (error) {
    console.error('获取数据失败:', error)
    ElMessage.error('获取数据失败，请重试')
  } finally {
    loading.value = false
  }
})

// 返回上一页
const goBack = () => {
  if (videoTimeout.value) {
    clearTimeout(videoTimeout.value)
    videoTimeout.value = null
  }
  router.replace(`/drama/edit/${dramaId.value}?tab=episode`)
}

// 加载分镜数据
const loadStoryboardData = async () => {
  try {
    storyboardLoading.value = true

    // 获取分镜数据
    const { data } = await getDramaStoryboard(seriesId.value, {
      pageSize: 1000,
      pageNum: 1
    })

    storyboardItems.value = data.records.map(item => ({
      ...item,
      modelProvider: item.modelProvider || 'JIMENG_4' // 如果API没有返回modelProvider，默认为'JIMENG_4'
    }))
    curStoryBoard.value = data.records[0]

    // 更新是否是第一次初始化
    isFirstInitStoryboard.value = storyboardItems.value.length === 0

    // 加载已确认的分镜图片
    await loadConfirmedStoryboardImages()
  } catch (error) {
    console.error('获取分镜数据失败:', error)
    ElMessage.error('获取分镜数据失败，请重试')
  } finally {
    storyboardLoading.value = false
  }
}

// 加载已确认的分镜图片
const loadConfirmedStoryboardImages = async () => {
  if (!seriesId.value) return

  try {
    const { data } = await getConfirmedStoryboardImages(seriesId.value)
    if (data && Array.isArray(data)) {
      // 转换数据格式
      selectedStoryboardImages.value = data.map(item => {
        return {
          url: item.imageUrl,
          sbNo: item.sbNo
        }
      })
    }
  } catch (error) {
    console.error('获取已确认分镜图片失败:', error)
  }
}

const changeStoryboardIndex = (index) => {
  // 停止当前分镜的轮询
  stopImagePolling()
  selectedImage.value.url = selectedStoryboardImages.value.find(item => item.sbNo === index + 1)?.url || ''
  selectedImage.value.resKey = ''
}

// 切换到指定标签的方法更新，加载相应数据
const switchToTab = (tabName) => {
  // 如果切换到图集标签，先检查所有分镜是否已确认
  // if (tabName === 'gallery' || tabName === 'video') {
  //   const hasUnconfirmedStoryboards = storyboardItems.value.some(item => item.status === 0);
  //   if (hasUnconfirmedStoryboards) {
  //     ElMessage.warning('请先确认所有分镜后再进行下一步');
  //     return;
  //   }
  // }
  if (tabName === 'video') {
    if(selectedStoryboardImages.value.length < 1) {
      ElMessage.warning('请至少确认一个图集后再进行下一步');
      return;
    }
  }

  if (tabName === 'storyboards' || tabName === 'gallery' || tabName === 'video') {
    storyboardActiveTab.value = tabName

    router.replace({
      query: {
        ...route.query,
        tab: tabName === 'storyboards' ? 1 : tabName === 'gallery' ? 2 : 3
      }
    });

    // 如果切换到图集标签，加载图集数据
    if (tabName === 'gallery') {
      // 重置当前分镜索引，确保从第一个分镜开始
      currentStoryboardIndex.value = 0;
      loadGalleryData();
    }
    if (tabName === 'video') {
      loadVideoListByStoryboard(curStoryBoard.value.sbId, curStoryBoard.value)
    }
      if (tabName !== 'video') {
    if (videoTimeout.value) {
      clearTimeout(videoTimeout.value)
      videoTimeout.value = null
    }
  }
  }
}

// 处理下一步按钮点击
const handleNextStep = () => {
  // 检查所有分镜是否已确认
  const hasUnconfirmedStoryboards = storyboardItems.value.some(item => item.status === 0);
  // if (hasUnconfirmedStoryboards) {
  //   ElMessage.warning('请先确认所有分镜后再进行下一步');
  //   return;
  // }

  // 切换到图集生成标签
  switchToTab('gallery');
}

// 添加分镜项目
const handleAddStoryboardItem = () => {
  // 创建一个新的分镜对象
  const newStoryboardItem = {
    sbNo: '',
    sbDesc: '',
    actors: [],
    status: 0, // 未确认状态
    dramaId: dramaId.value,
    seriesId: seriesId.value,
    modelProvider: 'JIMENG_4'
  }

  // 将新分镜添加到数组顶部
  storyboardItems.value = [newStoryboardItem, ...storyboardItems.value]

  // 重新编号所有分镜
  storyboardItems.value = storyboardItems.value.map((item, index) => {
    if (index > 0) {
      // 保留原有分镜的编号
      return item
    } else {
      // 新添加的分镜保持"补充分镜"的名称
      return item
    }
  })
}



// 处理角色变化
const handleActorChange = (index) => {
  const actor = storyboardItemForm.actors[index]
  // 重置预览图片
  actor.previewUrl = ''

  // 根据选择的actorId查找对应的角色信息
  const selectedRole = roles.value.find(role => role.actorId === actor.actorId)

  if (selectedRole) {
    // 设置actorName
    actor.actorName = selectedRole.actorName
  }
}

// 更新角色预览图片
const updateActorPreview = (index) => {
  const actor = storyboardItemForm.actors[index]
  const selectedRole = roles.value.find(role => role.actorId === actor.actorId)

  if (!selectedRole) return
}

// 处理列表中的角色变化
const handleActorChangeInList = (actor, item, index) => {
  // 根据选择的actorId查找对应的角色信息
  const selectedRole = roles.value.find(role => role.actorId === actor.actorId)

  if (selectedRole) {
    // 设置actorName
    actor.actorName = selectedRole.actorName
  }
}

// 处理列表中的视角变化
const handlePerspectiveChangeInList = (actor, item, index) => {
  // 这里可以添加额外的逻辑
}

// 处理分镜项变更
const handleItemChange = (item, index) => {
  // 可以在这里添加自动保存逻辑
}

// 处理选择场景
const handleSelectScene = (item, index) => {
  // 存储当前正在编辑的分镜项目和索引
  selectedStoryboardItem.value = item
  selectedStoryboardIndex.value = index

  // 重置表单数据
  sceneForm.sceneId = item.sceneId || ''
  sceneForm.sceneName = ''
  sceneForm.previewUrl = item.sceneUrl || ''

  // 打开弹窗
  sceneDialogVisible.value = true

  // 重置表单校验
  nextTick(() => {
    sceneFormRef.value && sceneFormRef.value.resetFields()
  })
}

// 场景选择变化处理
const handleSceneChange = (sceneId) => {
  // 根据选择的sceneId查找对应的场景信息
  const selectedScene = scenes.value.find(scene => scene.sceneId === sceneId)

  if (selectedScene) {
    // 设置sceneName
    sceneForm.sceneName = selectedScene.sceneName
    sceneForm.sceneResKey = selectedScene.sceneResKey

    // 设置场景预览图
    sceneForm.previewUrl = selectedScene.previewUrl || ''
  }
}

// 确认场景选择
const handleConfirmSelectScene = async () => {
  // 表单验证
  if (!sceneFormRef.value) return

  try {
    await sceneFormRef.value.validate()

    if (selectedStoryboardItem.value && selectedStoryboardIndex.value >= 0) {
      // 根据选择的sceneId查找对应的场景信息
      const selectedScene = scenes.value.find(scene => scene.sceneId === sceneForm.sceneId)

      // 更新分镜项目的场景信息
      const updatedItem = { ...selectedStoryboardItem.value }
      updatedItem.sceneId = sceneForm.sceneId
      updatedItem.sceneName = sceneForm.sceneName
      updatedItem.sceneResKey = sceneForm.sceneResKey
      updatedItem.sceneUrl = selectedScene?.sceneImageUrl || sceneForm.previewUrl // 优先使用场景的图片URL

      // 更新分镜项目数组
      const updatedItems = [...storyboardItems.value]
      updatedItems[selectedStoryboardIndex.value] = updatedItem
      storyboardItems.value = updatedItems

      // 关闭弹窗
      sceneDialogVisible.value = false

      ElMessage.success('场景设置成功')
    }
  } catch (error) {
    console.error('表单验证失败:', error)
    ElMessage.error('表单验证失败，请检查输入')
  }
}

// 处理创建场景
const handleCreateScene = (item, index) => {
  selectedStoryboardItem.value = item
  selectedStoryboardIndex.value = index

  // 重置表单
  createSceneForm.sceneName = ''
  createSceneForm.sceneDesc = ''
  createSceneForm.seqNo = currentEpisode.value?.seqNo || ''
  createSceneForm.sceneImageUrl = ''

  // 设置上传类型为本地上传
  uploadType.value = 'local'

  // 加载剧集列表
  fetchSeriesList()

  // 打开弹窗
  createSceneDialogVisible.value = true

  // 重置表单校验
  nextTick(() => {
    createSceneFormRef.value && createSceneFormRef.value.resetFields()
  })
}

// 加载剧集列表
const fetchSeriesList = async () => {
  if (!dramaId.value) return

  try {
    loadingSeries.value = true
    const { data } = await getDramaSeries(dramaId.value)
    if (data && Array.isArray(data)) {
      seriesList.value = data
    } else {
      seriesList.value = []
    }
  } catch (error) {
    console.error('获取剧集列表失败:', error)
    ElMessage.error('获取剧集列表失败')
    seriesList.value = []
  } finally {
    loadingSeries.value = false
  }
}

// 保存场景创建
const saveCreateSceneLoading = ref(false)

const handleSaveCreateScene = async () => {
  try {
    // 表单验证
    if (!createSceneFormRef.value) return

    await createSceneFormRef.value.validate()

    // 如果是本地上传且没有上传图片，提示用户
    if (uploadType.value === 'local' && !createSceneForm.sceneResKey) {
      ElMessage.warning('请上传场景图片')
      return
    }

    // 如果是本地上传但没有获取到sceneResKey，提示用户
    if (uploadType.value === 'local' && !createSceneForm.sceneResKey) {
      ElMessage.warning('图片上传未完成，请重新上传')
      return
    }

    saveCreateSceneLoading.value = true

    // 构造场景数据
    const sceneData = {
      name: createSceneForm.sceneName,
      desc: createSceneForm.sceneDesc,
      seriesNo: createSceneForm.seqNo,
      sceneImageUrl: createSceneForm.sceneImageUrl,
      sceneResKey: createSceneForm.sceneResKey, // 添加sceneResKey字段
      dramaId: dramaId.value,
      uploadType: uploadType.value
    }

    try {
      if (uploadType.value === 'local') {
        // 调用创建场景API
        const { data } = await createScene(sceneData)
        // 获取场景数据
        const { data: sceneList } = await getDramaScene(dramaId.value)
        if (sceneList) {
          scenes.value = sceneList
        }
        const curScene = scenes.value.find(item => item.sceneResKey === createSceneForm.sceneResKey)
        // 本地上传模式，更新当前分镜的场景
        if (selectedStoryboardItem.value && selectedStoryboardIndex.value >= 0) {
          // 更新分镜项目的场景信息
          const updatedItem = { ...selectedStoryboardItem.value }
          updatedItem.sceneResKey = curScene.sceneResKey
          updatedItem.sceneUrl = curScene.sceneImageUrl // 使用场景图片URL
          updatedItem.sceneDesc = curScene.sceneName // 使用场景图片URL

          // 更新分镜项目数组
          const updatedItems = [...storyboardItems.value]
          updatedItems[selectedStoryboardIndex.value] = updatedItem
          storyboardItems.value = updatedItems

          ElMessage.success('场景创建并应用成功')
        }
      } else {
        await createSceneByAI(sceneData)
        // AI生成模式，跳转到场景管理页面
        ElMessage.success('场景创建成功，即将跳转到场景管理页面确认AI场景')
        setTimeout(() => {
          router.push(`/drama/edit/${dramaId.value}?tab=scene`)
        }, 1500)
      }

      // 关闭弹窗
      createSceneDialogVisible.value = false
    } catch (error) {
      console.error('创建场景失败:', error)
      ElMessage.error('创建场景失败，请重试')
    }
  } catch (error) {
    console.error('表单验证失败:', error)
  } finally {
    saveCreateSceneLoading.value = false
  }
}

// 保存分镜项目
const handleSaveStoryboardItem = async (item, index, showPic = false) => {
  try {

    // 显示加载状态
    savingStoryboard.value = true

    // 调用确认接口
    const result = await confirmStoryboard({
      ...item,
      sbNo: item.sbNo ? item.sbNo : storyboardItems.value.length,
      perspective: item.perspective ? item.perspective : 'EMPTY',
      actorId: item.actorId ? item.actorId : undefined,
      actorParamList: item.actorVOList ? item.actorVOList : [],
      shotType: undefined
    })

    // 保存成功
    ElMessage.success(item.status === 0 ? '分镜确认成功' : '分镜修改成功')

    // 重新获取分镜列表
    let currentItems = []
    currentItems = storyboardItems.value.map((story, storyIndex) => {
      if (storyIndex === index) {
        return {
          ...item,
          status: 1,
          sbId: result.data
        }
      }
      return story
    })
    if (!item.sbNo) {
      currentItems = [...currentItems.slice(1), {
        ...currentItems[0],
        sbNo: storyboardItems.value.length
      }]
    }
    storyboardItems.value = currentItems
    if (showPic) {
      // 显示加载状态
      isImageProcessing.value = true;
      setTimeout(() => {
        loadGalleryForStoryboard(item.sbId)
      }, 4000)
    }
  } catch (error) {
    console.error('保存分镜失败:', error)
    ElMessage.error('保存分镜失败，请重试')
  } finally {
    savingStoryboard.value = false
  }
}

// 删除分镜项目
const handleDeleteStoryboardItem = (index) => {
  ElMessageBox.confirm('确定要删除该分镜吗？', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning',
    confirmButtonClass: 'confirm-delete-btn-class'
  }).then(async () => {
    try {
      const item = storyboardItems.value[index]

      // 如果是新添加的分镜（没有sbId），直接从前端删除
      if (!item.sbId) {
        const updatedItems = [...storyboardItems.value]
        updatedItems.splice(index, 1)
        storyboardItems.value = updatedItems
        ElMessage.success('分镜删除成功')
        return
      }

      // 调用删除API
      await deleteStoryboard(item.sbId)

      // 执行前端删除逻辑
      const updatedItems = [...storyboardItems.value]
      updatedItems.splice(index, 1)
      storyboardItems.value = updatedItems

      ElMessage.success('分镜删除成功')
    } catch (error) {
      console.error('删除分镜失败:', error)
      ElMessage.error('删除失败，请重试')
    }
  }).catch(() => { })
}

// 计算选中的图片
const selectedImage = ref({
  url: '',
  resKey: ''
})

// 已选中的分镜图片
const selectedStoryboardImages = ref([])

// 计算当前选中的分镜
const currentStoryboard = computed(() => {
  if (!storyboardItems.value.length || currentStoryboardIndex.value < 0 || currentStoryboardIndex.value >= storyboardItems.value.length) {
    return null;
  }
  return storyboardItems.value[currentStoryboardIndex.value];
})

// 当前预览图片
const currentPreviewImage = computed(() => {
  if (selectedStoryboardImages.value.length > 0 &&
    previewImageIndex.value >= 0 &&
    previewImageIndex.value < selectedStoryboardImages.value.length) {
    return selectedStoryboardImages.value[previewImageIndex.value]
  }
  return null
})

// 判断是否有角色
const hasRoles = computed(() => {
  return roles.value && roles.value.length > 0
})

// 判断是否有场景
const hasScenes = computed(() => {
  return scenes.value && scenes.value.length > 0
})

// 选择图片
const handleSelectImage = (image) => {
  console.log('handleSelectImage', image)
  if(image?.dataStatus === 3) return
  if(selectedImageUrl.value === image.url) {
    previewVisible.value = true
    previewImageUrl.value = image.url
    return
  }
  selectedImageUrl.value = image.url
  // 设置提示词，优先使用图片的prompt，如果没有则使用从API获取的videoPrompt
  selectedImagePrompt.value = image.prompt || ''
  selectedImage.value.url = image.url
  selectedImage.value.resKey = image.resKey
}
watch(selectedModel, () => {
  if (selectedModel.value === 'sora2') {
    selectedDuration.value = 8
  } else if(selectedModel.value === 'sora2-duomi') {
    selectedDuration.value = 10
  } else {
    selectedDuration.value = 5
  }
}, {immediate: true})

watch(videoModel, () => {
  if (videoModel.value === 'sora2') {
    videoDuration.value = 8
  } else if (videoModel.value === 'sora2-duomi') {
    videoDuration.value = 10
  } else {
    videoDuration.value = 5
  }
}, {immediate: true})
// 监听当前分镜索引变化
watch(currentStoryboardIndex, async (newIndex) => {
  if (!currentEpisode.value) return;

  try {
    // 获取当前分镜的图片列表
    if (storyboardItems.value.length > 0 && newIndex >= 0 && newIndex < storyboardItems.value.length) {
      // 在此处加载当前分镜的图片列表
      const currentStoryboard = storyboardItems.value[newIndex];
      // 否则调用API获取数据
      await loadGalleryForStoryboard(currentStoryboard.sbId);
    } else {
      galleryImages.value = [];
    }

    // 重置选中状态
    selectedImageUrl.value = '';
    selectedImagePrompt.value = '';

  } catch (error) {
    console.error('获取分镜图片数据失败:', error);
    ElMessage.error('获取分镜图片失败，请重试');
  }
})

const videoTimeout = ref(null)
// 轮询加载视频
const intervalLoadVideo = (sbId, sb) => {
  // 使用普通变量存储setTimeout的返回值
  const timeoutId = setTimeout(async () => {
    try {
      const { data } = await queryStoryboardVideoList(dramaId.value, sbId);
      if (!data) return; // 防止数据为空时的错误
      
      storyboardVideoLoading.value = data.processing
      loadingVideoStep3.value = data.processing
      if (data && data.videoProcess) {
        if (data.processing) {
          // 递归调用前清除上一个定时器
          if (videoTimeout.value) {
            clearTimeout(videoTimeout.value);
          }
          intervalLoadVideo(sbId, sb);
        } else {
          storyboardVideoList.value = data.videoProcess;
          if (sb && sb.videoUrl) {
            // 确保videoUrl存在再进行比较
            curVideoUrl.value = storyboardVideoList.value.find(item => 
              item.videoUrl && item.videoUrl.includes(sb.videoUrl?.split('?')[0])
            )?.videoUrl || '';
          }
        }
      }
    } catch (error) {
      console.error('轮询加载视频失败:', error);
    }
  }, 5000);
  
  // 将timeoutId存储到ref中
  videoTimeout.value = timeoutId;
}

// 加载视频数据
const loadVideoListByStoryboard = async (sbId, sb) => {
  try {
    // 清除之前的定时器
    if (videoTimeout.value) {
      clearTimeout(videoTimeout.value);
      videoTimeout.value = null;
    }
    
    const { data } = await queryStoryboardVideoList(dramaId.value, sbId);
    if (!data) return; // 防止数据为空时的错误
    storyboardVideoLoading.value = data.processing;
    loadingVideoStep3.value = data.processing;
    if (data && data.videoProcess) {
      if (data.processing) {
        // 如果正在处理中，开始轮询
        storyboardVideoList.value = data.videoProcess;
        if (sb && sb.videoUrl) {
          // 确保videoUrl存在再进行比较
          curVideoUrl.value = storyboardVideoList.value.find(item => 
            item.videoUrl && item.videoUrl.includes(sb.videoUrl?.split('?')[0])
          )?.videoUrl || '';
        } else {
          curVideoUrl.value = ''
        }
        intervalLoadVideo(sbId, sb);
      } else {
        // 如果已经处理完成，直接更新数据
        storyboardVideoList.value = data.videoProcess;
        if (sb && sb.videoUrl) {
          // 确保videoUrl存在再进行比较
          curVideoUrl.value = storyboardVideoList.value.find(item => 
            item.videoUrl && item.videoUrl.includes(sb.videoUrl?.split('?')[0])
          )?.videoUrl || '';
        } else {
          curVideoUrl.value = ''
        }
      }
    }
  } catch (error) {
    console.error('加载视频数据失败:', error);
  }
}

// 为特定分镜加载图集
const loadGalleryForStoryboard = async (sbId) => {
  try {
    // 显示加载状态
    refreshingImages.value = true;

    // 调用API获取图集列表
    const { data } = await queryStoryboardImageList(dramaId.value, sbId);

    if (data && data.imageProcess) {
      // 检查是否有正在处理中的图片
      isImageProcessing.value = data.imageProcess.processing || false;

      // 如果正在处理中，启动轮询
      if (isImageProcessing.value) {
        startImagePolling();
      }

      if (data.imageProcess.imageTaskList) {
        const imageList = data.imageProcess.imageTaskList.map(image => ({
          ...image,
          resKey: image.resKey || image.fileKey || '' // 确保每个图片都有resKey属性
        }));

        // 存入map中
        storyboardGalleries.value.set(sbId, imageList);

        console.log(imageList)

        // 更新当前显示的图集
        galleryImages.value = imageList

        // 如果有已确认的图片URL，将其设置为左侧选中图片
        if (data.confirmedImageUrl) {
          selectedImage.value.url = data.confirmedImageUrl
        } else {
          // 如果没有确认的图片，重置选中状态
          selectedImageUrl.value = '';
          selectedImagePrompt.value = '';
        }
      } else {
        galleryImages.value = [];

        // 如果有已确认的图片URL，但没有图片列表，创建一个包含已确认图片的列表
        if (data.confirmedImageUrl) {
          const confirmedImage = {
            url: data.confirmedImageUrl,
            resKey: data.confirmedImageResKey || '',
            isConfirmed: true
          };
          galleryImages.value = [confirmedImage];
          selectedImageUrl.value = galleryImages.value[0].url;
        } else {
          selectedImageUrl.value = '';
          selectedImagePrompt.value = '';
        }
      }
    } else {
      galleryImages.value = [];
      selectedImageUrl.value = '';
      selectedImagePrompt.value = '';
    }
  } catch (error) {
    console.error('获取分镜图片列表失败:', error);
    ElMessage.error('获取分镜图片列表失败，请重试');
    galleryImages.value = [];
  } finally {
    refreshingImages.value = false;
  }
};

// 上一个分镜
const handlePrevStoryboard = () => {
  if (currentStoryboardIndex.value > 0) {
    // 停止当前分镜的轮询
    stopImagePolling()
    currentStoryboardIndex.value--
    selectedImage.value.url = selectedStoryboardImages.value.find(item => item.sbNo === currentStoryboardIndex.value + 1)?.url || ''
    selectedImage.value.resKey = ''
  }
}

// 下一个分镜
const handleNextStoryboard = () => {
  if (currentStoryboardIndex.value < storyboardItems.value.length - 1) {
    // 停止当前分镜的轮询
    stopImagePolling()
    currentStoryboardIndex.value++
    selectedImage.value.url = selectedStoryboardImages.value.find(item => item.sbNo === currentStoryboardIndex.value + 1)?.url || ''
    selectedImage.value.resKey = ''
  }
}

// 设定为用图
const handleSetAsStoryboardImage = async () => {
  if (!selectedImage.value || !currentEpisode.value || currentStoryboardIndex.value < 0 || storyboardItems.value.length === 0) {
    ElMessage.error('请先选择图片和分镜')
    return
  }

  const selectedStoryboard = storyboardItems.value[currentStoryboardIndex.value]
  if (!selectedStoryboard) {
    ElMessage.error('请先选择分镜')
    return
  }

  if (!selectedStoryboard.sbId) {
    ElMessage.error('分镜ID不存在，无法保存')
    return
  }

  if (!selectedImage.value.resKey && !selectedImage.value.url) {
    ElMessage.error('图片资源键不存在，请重新上传图片')
    return
  }

  try {
    // 显示加载状态
    const loading = ElLoading.service({
      lock: true,
      text: '保存中...'
    })
    let params = {}
    if (selectedStoryboard.sbId) {
      params.sbId = selectedStoryboard.sbId
    }
    if (selectedImage.value.resKey) {
      params.resKey = selectedImage.value.resKey
    }
    // 调用API保存选中的图片
    await confirmStoryboardImage(params)

    const updatedStoryboard = { ...selectedStoryboard }
    updatedStoryboard.selectedImage = selectedImage.value.url
    updatedStoryboard.selectedImageResKey = selectedImage.value.resKey

    const updatedItems = [...storyboardItems.value]
    updatedItems[currentStoryboardIndex.value] = updatedStoryboard
    storyboardItems.value = updatedItems

    // 重新加载已确认的分镜图片
    await loadConfirmedStoryboardImages()

    loading.close()
    ElMessage.success('已设定为用图')
  } catch (error) {
    console.error('设置用图失败:', error)
    ElMessage.error('设置用图失败，请重试')
  }
}

const exportLoading = ref(false)

const pollExportImage = async (dramaId, seriesId) => {
  const response = await exportStoryboardImages(dramaId, seriesId)
  if (response.data.status === 4) {
    exportLoading.value = false
    window.open(response.data.url, '_blank')
    ElMessage.success('分镜图导出成功')
  } else {
    setTimeout(() => {
      pollExportImage(dramaId, seriesId)
    }, 5000);
  }
}
// 导出分镜图
const exportImage = async () => {
  try {
    exportLoading.value = true

    // 调用导出API
    const response = await reExportStoryboardImagesAgain(dramaId.value, seriesId.value)

    // 检查响应
    if (response.data.status === 4) {
      // 直接打开下载链接
      exportLoading.value = false
      window.open(response.data.url, '_blank')
      ElMessage.success('分镜图导出成功')
    } else {
      pollExportImage(dramaId.value, seriesId.value)
      // ElMessage.error('导出失败，返回数据为空或缺少下载链接')
    }
  } catch (error) {
    console.error('导出分镜图失败:', error)
    ElMessage.error('导出分镜图失败，请重试')
  }
}

onUnmounted(() => {
  // 清除图片处理轮询定时器
  if (videoTimeout.value) {
    clearTimeout(videoTimeout.value)
    videoTimeout.value = null
  }
  stopImagePolling()
})

// 格式化时间戳
const formatTime = (timestamp) => {
  if (!timestamp) return '-'
  return dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')
}

// 获取状态文本
const getStatusText = (status) => {
  switch (status) {
    case 0:
      return '待确认'
    case 1:
      return '生成中'
    case 2:
      return '已完成'
    default:
      return '待确认'
  }
}

// 获取状态样式类
const getStatusClass = (status) => {
  switch (status) {
    case 0:
      return 'status-pending'
    case 1:
      return 'status-generating'
    case 2:
      return 'status-completed'
    default:
      return 'status-pending'
  }
}

// 加载图集数据的方法
const loadGalleryData = async () => {
  try {
    // 如果当前没有选中分镜，默认选择第一个
    if (storyboardItems.value.length > 0 && currentStoryboardIndex.value < 0) {
      currentStoryboardIndex.value = 0;
    }

    // 加载已确认的分镜图片
    await loadConfirmedStoryboardImages();

    // 加载当前分镜的图集
    if (storyboardItems.value.length > 0 && currentStoryboardIndex.value >= 0) {
      const currentStoryboard = storyboardItems.value[currentStoryboardIndex.value];

      if (!currentStoryboard.sbId) {
        galleryImages.value = [];
        return;
      }

      // 如果storyboardGalleries中已有该sbId的数据，直接使用
      if (storyboardGalleries.value.has(currentStoryboard.sbId)) {
        galleryImages.value = storyboardGalleries.value.get(currentStoryboard.sbId);

        // 如果有图片，自动选中第一张
        if (galleryImages.value.length > 0) {
          selectedImageUrl.value = galleryImages.value[0].url;
          selectedImagePrompt.value = galleryImages.value[0].prompt || '';
          selectedImage.value.url = galleryImages.value[0].url;
          selectedImage.value.resKey = galleryImages.value[0].resKey || '';
        } else {
          selectedImageUrl.value = '';
          selectedImagePrompt.value = '';
          selectedImage.value.url = '';
          selectedImage.value.resKey = '';
        }
      } else {
        // 否则调用API获取数据
        await loadGalleryForStoryboard(currentStoryboard.sbId);
      }
    }
  } catch (error) {
    console.error('加载图集数据失败:', error);
    ElMessage.error('加载图集数据失败，请重试');
  }
};

// 场景选择弹窗
const sceneDialogVisible = ref(false)
const selectedStoryboardItem = ref(null)
const selectedStoryboardIndex = ref(-1)
const sceneFormRef = ref(null)
const sceneForm = reactive({
  sceneId: '',
  sceneName: '',
  previewUrl: '',
  sceneResKey: ''
})
const sceneRules = {
  sceneId: [
    { required: true, message: '请选择场景', trigger: 'change' }
  ]
}

// 场景创建弹窗
const createSceneDialogVisible = ref(false)
const createSceneFormRef = ref(null)
const createSceneForm = reactive({
  sceneName: '',
  sceneDesc: '',
  seqNo: '',
  sceneImageUrl: '',
  sceneResKey: '' // 添加sceneResKey字段存储上传后的fileKey
})
const createSceneRules = {
  sceneName: [
    { required: true, message: '请输入场景名称', trigger: 'blur' },
    { max: 50, message: '场景名称长度不能超过50个字符', trigger: 'blur' }
  ],
  sceneDesc: [
    { required: true, message: '请输入场景描述', trigger: 'blur' },
    { max: 200, message: '场景描述长度不能超过200个字符', trigger: 'blur' }
  ],
  seqNo: [
    { required: true, message: '请选择所属剧集', trigger: 'change' }
  ]
}

// 上传方式切换
const uploadType = ref('local')
const loadingSeries = ref(false)
const seriesList = ref([])

// 上传场景图片
const beforeImageUpload = (file) => {
  saveCreateSceneLoading.value = true
}

// 处理场景图片上传
const handleCreateSceneImageUpload = async (fileKey) => {
  createSceneForm.sceneResKey = fileKey
  saveCreateSceneLoading.value = false
}

// 角色选择弹窗
const actorDialogVisible = ref(false)
const selectedStoryboardItemForActor = ref(null)
const selectedStoryboardIndexForActor = ref(-1)

// 多角色选择表单
const actorForms = ref([])

// 初始化角色表单项
const createActorFormItem = () => ({
  actorId: '',
  perspective: '',
  actorName: '',
  imageUrl: ''
})

// 计算选中的角色（为兼容性保留，但现在主要使用getSelectedActor函数）
const selectedActor = computed(() => {
  if (!roles.value.length) return null
  // 返回第一个有选中角色的表单项对应的角色
  const firstForm = actorForms.value.find(form => form.actorId)
  if (!firstForm) return null
  return roles.value.find(role => role.actorId === firstForm.actorId)
})

// 获取指定表单项的选中角色
const getSelectedActor = (actorId) => {
  if (!actorId || !roles.value.length) return null
  return roles.value.find(role => role.actorId === actorId)
}

// 处理选择角色
const handleSelectActor = (item, index) => {
  selectedStoryboardItemForActor.value = item
  selectedStoryboardIndexForActor.value = index

  // 初始化多角色表单
  initializeActorForms(item)

  actorDialogVisible.value = true
}

// 初始化角色表单
const initializeActorForms = (item) => {
  if (item.actorVOList && item.actorVOList.length > 0) {
    // 使用actorVOList初始化
    actorForms.value = item.actorVOList.map(actor => ({
      actorId: actor.actorId || '',
      perspective: actor.perspective || '',
      actorName: actor.actorName || '',
      imageUrl: actor.actorImageUrl || ''
    }))
  } else {
    // 如果没有actorVOList，创建一个空的表单项
    actorForms.value = [createActorFormItem()]
  }

  // 确保至少有一个表单项
  if (actorForms.value.length === 0) {
    actorForms.value = [createActorFormItem()]
  }
}

// 添加新的角色表单项
const addActorForm = () => {
  if (actorForms.value.length >= 5) {
    ElMessage.warning('最多只能选择5个角色')
    return
  }
  actorForms.value.push(createActorFormItem())
}

// 删除角色表单项
const removeActorForm = (index) => {
  if (actorForms.value.length <= 1) {
    ElMessage.warning('至少需要保留一个角色')
    return
  }
  actorForms.value.splice(index, 1)
}

// 处理单个角色选择变化
const handleActorSelectChange = (index, actorId) => {
  // 找到对应的表单项
  const formItem = actorForms.value[index]
  if (!formItem) return

  // 重置视图选择
  formItem.perspective = ''

  // 更新角色名称
  const selectedRole = getSelectedActor(actorId)
  if (selectedRole) {
    formItem.actorName = selectedRole.actorName
    formItem.actorId = actorId
  }
}

// 处理单个角色视图变化
const handlePerspectiveChange = (index, perspective) => {
  const formItem = actorForms.value[index]
  if (!formItem) return

  formItem.perspective = perspective

  // 更新图片URL
  const selectedRole = getSelectedActor(formItem.actorId)
  if (selectedRole) {
    switch (perspective) {
      case 'WHOLE_BODY_FRONT':
        formItem.imageUrl = selectedRole.wholeBodyFrontImageUrl
        break
      case 'WHOLE_BODY_SIDE':
        formItem.imageUrl = selectedRole.wholeBodySideImageUrl
        break
      case 'WHOLE_BODY_BACK':
        formItem.imageUrl = selectedRole.wholeBodyBackImageUrl
        break
      case 'HALF_BODY':
        formItem.imageUrl = selectedRole.halfBodyImageUrl
        break
      default:
        formItem.imageUrl = ''
    }
  }
}

// 选择角色视图
const selectActorView = (view) => {
  actorForm.perspective = view
}

// 确认角色选择
const handleConfirmSelectActor = () => {
  // 验证所有表单项
  const invalidForms = actorForms.value.filter(form => !form.actorId || !form.perspective)
  if (invalidForms.length > 0) {
    ElMessage.warning('请为所有角色选择角色和视图')
    return
  }

  if (selectedStoryboardItemForActor.value && selectedStoryboardIndexForActor.value >= 0) {
    // 构建actorVOList
    const actorVOList = actorForms.value.map(form => ({
      actorId: form.actorId,
      actorName: form.actorName,
      actorImageUrl: form.imageUrl,
      perspective: form.perspective
    }))

    // 更新分镜项目的角色信息
    const updatedItem = { ...selectedStoryboardItemForActor.value }
    updatedItem.actorVOList = actorVOList

    // 为了兼容性，也设置第一个角色的信息到原有字段
    if (actorVOList.length > 0) {
      updatedItem.actorId = actorVOList[0].actorId
      updatedItem.actorName = actorVOList[0].actorName
      updatedItem.actorImageUrl = actorVOList[0].actorImageUrl
      updatedItem.perspective = actorVOList[0].perspective
    }

    // 检查模型兼容性：多角色不支持MJ模型
    const isMultiActor = actorVOList.length >= 2
    const isMJModel = updatedItem.modelProvider === 'MJ'
    
    if (isMultiActor && isMJModel) {
      // 多角色且当前是MJ模型，自动切换为JIMENG_4模型
      updatedItem.modelProvider = 'JIMENG_4'
      ElMessage.info('多角色场景不支持图片V1，已自动切换为即梦4')
    }

    // 更新分镜项目数组
    const updatedItems = [...storyboardItems.value]
    updatedItems[selectedStoryboardIndexForActor.value] = updatedItem
    storyboardItems.value = updatedItems

    // 关闭弹窗
    actorDialogVisible.value = false

    ElMessage.success('角色设置成功')
  }
}

// 删除角色
const handleRemoveActor = (item, index, actorIndex) => {
  if (!item) return

  // 更新分镜项目的角色信息
  const updatedItem = { ...item }

  // 如果提供了actorIndex，说明是删除多角色中的特定角色
  if (actorIndex !== undefined && updatedItem.actorVOList && updatedItem.actorVOList.length > 0) {
    // 从actorVOList数组中删除指定的角色
    const updatedActorVOList = [...updatedItem.actorVOList]
    updatedActorVOList.splice(actorIndex, 1)
    updatedItem.actorVOList = updatedActorVOList

    // 如果删除了所有角色，清空旧的单角色字段
    if (updatedActorVOList.length === 0) {
      updatedItem.actorId = ''
      updatedItem.actorName = ''
      updatedItem.actorImageUrl = ''
      updatedItem.perspective = ''
    } else {
      // 如果还有角色，将第一个角色设为主要角色（兼容旧逻辑）
      updatedItem.actorId = updatedActorVOList[0].actorId
      updatedItem.actorName = updatedActorVOList[0].actorName
      updatedItem.actorImageUrl = updatedActorVOList[0].actorImageUrl
      updatedItem.perspective = updatedActorVOList[0].perspective
    }
  } else {
    // 兼容旧逻辑：清空单角色字段
    updatedItem.actorId = ''
    updatedItem.actorName = ''
    updatedItem.actorImageUrl = ''
    updatedItem.perspective = ''
    updatedItem.actorVOList = []
  }

  // 检查模型兼容性：如果删除后还剩2个或更多角色，且当前是MJ模型，需要切换
  const remainingActorCount = updatedItem.actorVOList?.length || 0
  const isMJModel = updatedItem.modelProvider === 'MJ'
  
  if (remainingActorCount >= 2 && isMJModel) {
    // 删除后仍有2个或以上角色，且是MJ模型，自动切换为JIMENG_4模型
    updatedItem.modelProvider = 'JIMENG_4'
    ElMessage.info('多角色场景不支持图片V1，已自动切换为即梦4')
  }

  // 更新分镜项目数组
  const updatedItems = [...storyboardItems.value]
  updatedItems[index] = updatedItem
  storyboardItems.value = updatedItems

  ElMessage.success('角色删除成功')
}

// 删除场景
const handleRemoveScene = (item, index) => {
  if (!item) return
  
  // 更新分镜项目的场景信息
  const updatedItem = { ...item }
  updatedItem.sceneId = ''
  updatedItem.sceneName = ''
  updatedItem.sceneUrl = ''
  updatedItem.sceneDesc = ''
  updatedItem.sceneResKey = ''

  // 更新分镜项目数组
  const updatedItems = [...storyboardItems.value]
  updatedItems[index] = updatedItem
  storyboardItems.value = updatedItems

  ElMessage.success('场景删除成功')
}

// 处理图像操作
const handleImageAction = async (action, image) => {
  if (!image || !image.taskId || isImageProcessing.value) return

  const actionNames = {
    enhance: '增强',
    refine: '精细',
    redraw: '重绘'
  }

  const actionMap = {
    enhance: 'VARY_HIGH',
    refine: 'VARY_LOW',
    redraw: 'REROLL'
  }

  try {
    isImageProcessing.value = true

    // 调用API执行图像操作
    await request({
      url: '/evox-drama/image/change?taskAction=' + actionMap[action] + '&taskId=' + image.taskId,
      method: 'post'
    })

    ElMessage.success(`${actionNames[action]}操作已提交，处理中...`)

    // 开始轮询检查处理状态
    startImagePolling()
  } catch (error) {
    console.error(`${actionNames[action]}失败:`, error)
    ElMessage.error(`${actionNames[action]}失败，请重试`)
    isImageProcessing.value = false
  }
}

// 处理图像编辑
const handleImageEdit = (image) => {
  if (!image || !image.url) {
    ElMessage.warning('图片信息不完整，无法编辑')
    return
  }
  
  // 设置编辑参数
  editingImageUrl.value = image.url
  editingBusinessType.value = image.businessType
  editingBusinessId.value = currentStoryboard.value?.sbId || ''
  
  // 打开图片编辑弹窗
  imageEditorVisible.value = true
}

// 处理图片编辑弹窗关闭
const handleImageEditorClose = () => {
  imageEditorVisible.value = false
  editingImageUrl.value = ''
  editingBusinessType.value = ''
  editingBusinessId.value = ''
}

// 处理图片编辑保存
const handleImageEditorSave = async (saveData) => {
  console.log('保存编辑后的图片:', saveData)
  
  if (saveData && saveData.fileKey && editingBusinessId.value) {
    try {
      // 显示加载状态
      const loading = ElLoading.service({
        lock: true,
        text: '保存中...'
      })
      
      // 调用confirmStoryboardImage接口
      const params = {
        sbId: editingBusinessId.value,
        resKey: saveData.fileKey
      }
      
      await confirmStoryboardImage(params)
      
      // 重新加载已确认的分镜图片
      await loadConfirmedStoryboardImages()
      
      // 重新加载当前分镜的图集数据
      if (currentStoryboard.value && currentStoryboard.value.sbId) {
        await loadGalleryForStoryboard(currentStoryboard.value.sbId)
      }
      
      // 立即更新当前分镜的显示图片（显示刚保存的图片）
      const currentSbNo = currentStoryboard.value?.sbNo || currentStoryboardIndex.value + 1
      const savedStoryboardImage = selectedStoryboardImages.value.find(img => img.sbNo === currentSbNo)
      
      if (savedStoryboardImage) {
        // 更新当前分镜的选中图片为刚保存的图片
        selectedImage.value.url = savedStoryboardImage.url
        selectedImage.value.resKey = ''
        console.log('已更新当前分镜显示为保存的图片:', savedStoryboardImage.url)
      } else {
        // 如果没有找到保存的图片，则清除选中状态
        selectedImageUrl.value = ''
        selectedImagePrompt.value = ''
        selectedImage.value.url = ''
        selectedImage.value.resKey = ''
      }
      
      loading.close()
      ElMessage.success('图片保存成功')
      
    } catch (error) {
      console.error('保存图片失败:', error)
      ElMessage.error('保存图片失败，请重试')
    }
  } else {
    ElMessage.warning('图片保存数据不完整')
  }
  
  // 关闭编辑弹窗
  handleImageEditorClose()
}

// 处理图片生成完成事件
const handleImageGenerationCompleted = async (eventData) => {
  console.log('图片编辑生成完成:', eventData)
  
  try {
    // 重新加载当前分镜的图集数据（标准图片生成/增强图片生成列表）
    if (currentStoryboard.value && currentStoryboard.value.sbId) {
      await loadGalleryForStoryboard(currentStoryboard.value.sbId)
      console.log('已刷新当前分镜的图集列表')
    }
    
    // 重新加载已确认的分镜图片
    await loadConfirmedStoryboardImages()
    console.log('已刷新已确认的分镜图片列表')
    
  } catch (error) {
    console.error('刷新图片列表失败:', error)
  }
}

// 开始轮询检查图片处理状态
const startImagePolling = () => {
  // 清除可能存在的定时器
  if (imagePollingTimer.value) {
    clearInterval(imagePollingTimer.value)
  }

  // 设置轮询间隔为3秒
  imagePollingTimer.value = setInterval(async () => {
    try {
      if (!currentStoryboard.value || !currentStoryboard.value.sbId) {
        stopImagePolling()
        return
      }

      // 调用API获取图集列表
      const { data } = await queryStoryboardImageList(dramaId.value, currentStoryboard.value.sbId)

      if (data && data.imageProcess) {
        // 如果不再处理中，停止轮询
        if (!data.imageProcess.processing) {
          // 更新图片列表
          if (data.imageProcess.imageTaskList) {
            const imageList = data.imageProcess.imageTaskList.map(image => ({
              ...image,
              resKey: image.resKey || image.fileKey || ''
            }))

            // 更新缓存和当前显示
            storyboardGalleries.value.set(currentStoryboard.value.sbId, imageList)
            galleryImages.value = imageList

            // 重置选中状态
            selectedImageUrl.value = ''
            selectedImagePrompt.value = ''
          }

          // 停止轮询
          stopImagePolling()
        }
      } else {
        // 如果没有获取到有效数据，也停止轮询
        stopImagePolling()
      }
    } catch (error) {
      console.error('轮询图片状态失败:', error)
      stopImagePolling()
    }
  }, 3000)
}

// 停止轮询
const stopImagePolling = () => {
  if (imagePollingTimer.value) {
    clearInterval(imagePollingTimer.value)
    imagePollingTimer.value = null
  }
  isImageProcessing.value = false
}

// 处理上传图片
const handleUploadClick = () => {
  // 触发文件上传输入框的点击事件
  document.getElementById('fileInput').click()
}

// 处理文件变化
const handleFileChange = async (e) => {
  const file = e.target.files[0]
  if (!file) return

  // 验证文件类型和大小
  if (!file.type.startsWith('image/')) {
    ElMessage.error('请上传图片文件')
    return
  }

  if (file.size > 5 * 1024 * 1024) {
    ElMessage.error('图片大小不能超过5MB')
    return
  }

  try {
    // 显示加载状态
    const loading = ElLoading.service({
      lock: true,
      text: '上传中...'
    })

    // 使用 FileReader 预览图片
    const reader = new FileReader()
    reader.readAsDataURL(file)

    // 上传文件获取 fileKey
    const res = await uploadFile(file)

    if (res.data && res.data.fileKey) {
      // 创建新的图片对象
      const newImage = {
        url: URL.createObjectURL(file),
        resKey: res.data.fileKey,
        fileName: file.name
      }

      // 设置为当前选中的图片
      selectedImageUrl.value = ''
      selectedImage.value.resKey = res.data.fileKey
      selectedImage.value.url = URL.createObjectURL(file)

      ElMessage.success('图片上传成功')
    } else {
      ElMessage.error('图片上传失败')
    }

    // 关闭加载状态
    loading.close()

    // 清空文件输入，以便再次选择同一文件
    e.target.value = ''
  } catch (error) {
    console.error('图片上传失败:', error)
    ElMessage.error('图片上传失败，请重试')
    e.target.value = ''
  }
}

// 导出素材弹窗
const exportDialogVisible = ref(false);
const selectedExportItems = ref([]);
const selectAllExport = ref(false);

// 打开导出素材弹窗
const confirmedVideo = ref([])
const openExportDialog = async () => {
  const { data } = await confirmedVideoList(seriesId.value)
  confirmedVideo.value = data
  exportDialogVisible.value = true;
  selectedExportItems.value = [];
  selectAllExport.value = false;
};

// 切换选择状态
const toggleExportSelection = (item) => {
  const sbId = item.sbId;
  if (!sbId) return;
  
  const index = selectedExportItems.value.indexOf(sbId);
  if (index === -1) {
    selectedExportItems.value.push(sbId);
  } else {
    selectedExportItems.value.splice(index, 1);
  }
  
  // 更新全选状态
  updateSelectAllState();
};

// 处理全选变化
const handleSelectAllChange = () => {
  const value = !selectAllExport.value
  selectAllExport.value = value
  if (value) {
    // 全选
    selectedExportItems.value = confirmedVideo.value
      .filter(item => item.sbId)
      .map(item => item.sbId);
  } else {
    // 取消全选
    selectedExportItems.value = [];
  }
};

// 更新全选状态
const updateSelectAllState = () => {
  const validItems = confirmedVideo.value.filter(item => item.sbId);
  selectAllExport.value = validItems.length > 0 && 
    selectedExportItems.value.length === validItems.length;
};

// 获取分镜图片URL
const getStoryboardImageUrl = (item) => {
  // 查找对应的分镜图片
  const storyboardImage = selectedStoryboardImages.value.find(img => img.sbNo === (item.sbNo || storyboardItems.value.indexOf(item) + 1));
  return storyboardImage?.url || item.imageUrl || "https://via.placeholder.com/150?text=无分镜图片";
};

// 确认导出
const exportVideo = async () => {
  if (selectedExportItems.value.length === 0) {
    ElMessage.warning('请至少选择一个分镜');
    return;
  }
  
  try {
    exportLoading.value = true;
    
    // 调用导出视频API
    const response = await exportStoryboardVideo(dramaId.value, seriesId.value, selectedExportItems.value);
    
    // 检查响应
    if (response.data.status === 4) {
      // 直接打开下载链接
      exportLoading.value = false;
      window.open(response.data.url, '_blank');
      ElMessage.success('视频素材导出成功');
      exportDialogVisible.value = false;
    } else {
      // 开始轮询检查导出状态
      pollExportVideo(dramaId.value, seriesId.value, selectedExportItems.value);
    }
  } catch (error) {
    console.error('导出素材失败:', error);
    ElMessage.error('导出素材失败，请重试');
    exportLoading.value = false;
  }
};

// 轮询检查视频导出状态
const pollExportVideo = async (dramaId, seriesId, sbIdList) => {
  try {
    const response = await exportStoryboardVideo(dramaId, seriesId, sbIdList);
    if (response.data.status === 4) {
      exportLoading.value = false;
      window.open(response.data.url, '_blank');
      ElMessage.success('视频素材导出成功');
      exportDialogVisible.value = false;
    } else {
      // 继续轮询
      setTimeout(() => {
        pollExportVideo(dramaId, seriesId, sbIdList);
      }, 5000);
    }
  } catch (error) {
    console.error('轮询视频导出状态失败:', error);
    exportLoading.value = false;
    ElMessage.error('导出视频素材失败，请重试');
  }
};

// 处理编辑剧集
const handleEditEpisode = () => {
  if (!currentEpisode.value) {
    ElMessage.error('当前没有可编辑的剧集')
    return
  }
  
  // 设置当前编辑的剧集
  currentEditingEpisode.value = currentEpisode.value
  
  // 填充表单数据，使用分集剧本的内容
  editEpisodeForm.seqNo = currentEpisode.value.seqNo
  editEpisodeForm.content = scriptContent.value || ''
  
  // 打开弹窗
  editEpisodeDialogVisible.value = true
  
  // 重置表单验证
  nextTick(() => {
    editEpisodeFormRef.value && editEpisodeFormRef.value.resetFields()
  })
}

// 确认编辑剧集
const handleConfirmEditEpisode = async () => {
  // 表单验证
  try {
    await editEpisodeFormRef.value.validate()
  } catch (error) {
    return
  }
  
  editEpisodeLoading.value = true
  
  try {
    const requestData = {
      seriesId: currentEditingEpisode.value.seriesId,
      dramaId: parseInt(dramaId.value),
      content: editEpisodeForm.content
    }
    
    const { data } = await updateSeries(requestData)
    
    if (data) {
      ElMessage.success('剧集修改成功')
      editEpisodeDialogVisible.value = false
      
      // 更新当前剧集的内容
      currentEpisode.value.content = editEpisodeForm.content
      scriptContent.value = editEpisodeForm.content
      
      // 触发emit事件通知父组件更新
      emit('update:episode', currentEpisode.value)
    } else {
      ElMessage.warning('修改失败，返回数据为空')
    }
  } catch (error) {
    console.error('修改剧集失败:', error)
    ElMessage.error('修改失败，请重试')
  } finally {
    editEpisodeLoading.value = false
  }
}

</script>

<style>
.image-fail-wrapper {
  width: 100%;
  font-size: 12px;
  height: 100%;
  color: #525466;
  border-radius: 10px;
  background: #A2A6B829;
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  gap: 8px;
  padding: 20px;
}

.image-fail-text {
  color:#3644E0;
  cursor: pointer;
}
.dialog-title {
  font-size: 16px;
  font-weight: 500;
  color: #1C1D29;
  line-height: 16px;
}

.image-upload-container {
  width: 100%;
}

/* 全局移除所有元素的焦点边框 */
* {
  outline: none !important;
}

*:focus,
*:focus-visible,
*:active {
  border-color: #EBEEF5 !important;
}

.el-button:focus,
.el-button:focus-visible,
.el-button:active,
.el-input__inner:focus,
.el-input__wrapper:focus,
.el-textarea__inner:focus,
.el-select:focus,
.el-checkbox:focus,
.el-radio:focus,
.el-switch:focus,
.el-dropdown:focus,
.el-message-box__headerbtn:focus,
.el-upload:focus,
.el-table__row:focus,
.el-table__row td:focus,
.el-table:focus,
.el-table__cell:focus,
.el-table-column:focus,
.el-table__column:focus,
.el-table__inner-wrapper:focus,
.el-table__body:focus,
.el-table__header:focus {
  border-color: #EBEEF5 !important;
}

/* Element Plus 组件样式覆盖 */

.el-button--success:focus,
.el-button--success:active {
  background-color: var(--el-color-success);
  border-color: var(--el-color-success);
}

.el-button--warning:focus,
.el-button--warning:active {
  background-color: var(--el-color-warning);
  border-color: var(--el-color-warning);
}

.el-button--danger:focus,
.el-button--danger:active {
  background-color: var(--el-color-danger);
  border-color: var(--el-color-danger);
}
</style>

<style scoped>
/* Tailwind-like utility classes for the converted React component */
.flex {
  display: flex;
}

.grid {
  display: grid;
}

.items-center {
  align-items: center;
}

.justify-between {
  justify-content: space-between;
}

.justify-center {
  justify-content: center;
}
.actor-select-header-close {
  display: flex;
  justify-content: space-between;
  margin-bottom: 22px;
  font-size: 16px;
  color: var(--text-color-primary);
  font-weight: 500;
}

.flex-wrap {
  flex-wrap: wrap;
}

.gap-2 {
  gap: 0.5rem;
}

.gap-6 {
  gap: 1.5rem;
}

.space-y-6>*+* {
  margin-top: 1.5rem;
}

.mb-1 {
  margin-bottom: 0.25rem;
}

.mb-2 {
  margin-bottom: 0.5rem;
}

.mb-3 {
  margin-bottom: 0.75rem;
}

.mb-6 {
  margin-bottom: 1.5rem;
}

.mb-8 {
  margin-bottom: 2rem;
}

.mt-4 {
  margin-top: 1rem;
}

.ml-2 {
  margin-left: 0.5rem;
}

.mx-4 {
  margin-left: 1rem;
  margin-right: 1rem;
}

.p-6 {
  padding: 1.5rem;
}

.px-4 {
  padding-left: 1rem;
  padding-right: 1rem;
}

.py-2 {
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
}

.py-4 {
  padding-top: 1rem;
  padding-bottom: 1rem;
}

.w-5 {
  width: 1.25rem;
}

.w-8 {
  width: 2rem;
}

.w-12 {
  width: 3rem;
}

.w-16 {
  width: 4rem;
}

.w-20 {
  width: 5rem;
}

.w-full {
  width: 100%;
}

.h-5 {
  height: 1.25rem;
}

.h-8 {
  height: 2rem;
}

.h-full {
  height: 100%;
}

.h-px {
  height: 1px;
}

.min-h-screen {
  min-height: 100vh;
}

.text-xs {
  font-size: 0.75rem;
}

.text-sm {
  font-size: 0.875rem;
}

.text-lg {
  font-size: 1.125rem;
}

.text-xl {
  font-size: 1.25rem;
}

.font-medium {
  font-weight: 500;
}

.font-semibold {
  font-weight: 600;
}

.font-bold {
  font-weight: 700;
}

.text-white {
  color: white;
}

.text-gray-500 {
  color: #6b7280;
}

.text-gray-700 {
  color: #4b5563;
}

.bg-white {
  background-color: white;
}

.bg-gray-50 {
  background-color: #f9fafb;
}

.bg-gray-100 {
  background-color: #f3f4f6;
}

.bg-gray-200 {
  background-color: #e5e7eb;
}

.bg-gray-300 {
  background-color: #d1d5db;
}

.bg-blue {
  background-color: #6470fa;
}

.bg-dark {
  background-color: #23293d;
}

.bg-darker {
  background-color: #1c1d29;
}

.border {
  border-width: 1px;
}

.border-b {
  border-bottom-width: 1px;
}

.border-gray-200 {
  border-color: #e5e7eb;
}

.border-gray-300 {
  border-color: #d1d5db;
}

.border-blue {
  border-color: #3644e0;
}

.border-transparent {
  border-color: transparent;
}

.rounded {
  border-radius: 0.25rem;
}

.rounded-md {
  border-radius: 0.375rem;
}

.rounded-lg {
  border-radius: 0.5rem;
}

.rounded-full {
  border-radius: 9999px;
}

.shadow-sm {
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
}

.overflow-hidden {
  overflow: hidden;
}

.object-cover {
  object-fit: cover;
}

.aspect-square {
  aspect-ratio: 1 / 1;
}

.aspect-3-4 {
  aspect-ratio: 3 / 4;
}

.aspect-3-5 {
  aspect-ratio: 3 / 5;
}

.grid-cols-4 {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

.grid-cols-12 {
  grid-template-columns: repeat(12, minmax(0, 1fr));
}

.col-span-2 {
  grid-column: span 2 / span 2;
}

.col-span-10 {
  grid-column: span 10 / span 10;
}

.container {
  width: 100%;
  max-width: 1280px;
  margin-left: auto;
  margin-right: auto;
}

.line-clamp-3 {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.hover-text-gray-700:hover {
  color: #4b5563;
}

.storyboard-detail {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 16px 24px;
}

.storyboard-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
}

.storyboard-header-left {
  display: flex;
  align-items: center;
}

.back-button {
  width: 22px;
  height: 22px;
  margin-right: 20px;
  cursor: pointer;
}

.episode-seq {
  font-size: 18px;
  font-weight: 600;
}

.storyboard-progress {
  display: flex;
  align-items: center;
}

.progress-item {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: row;
  gap: 8px;
  cursor: pointer;
}

.progress-circle {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background-color: #fff;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 14px;
  font-weight: 600;
  transition: all 0.2s ease;
}

.progress-item.active .progress-circle {
  background-color: #3644E0;
  color: white;
}

.progress-text {
  font-size: 16px;
  color: #606266;
}

.progress-item.active .progress-text {
  color: #3644E0;
  font-weight: 500;
}

.progress-line {
  height: 2px;
  background-color: #e4e7ed;
  flex-grow: 1;
  width: 22px;
  margin: 0 12px;
}

.storyboard-content {
  display: flex;
  gap: 20px;
  flex: 1;
  margin-top: 24px;
  overflow: hidden;
}

.script-area {
  flex: 0.35;
  display: flex;
  flex-direction: column;
  padding: 20px;
}

.script-title {
  font-size: 18px;
  font-weight: 600;
  margin-bottom: 15px;
  color: #303133;
}

.script-content {
  font-size: 14px;
  line-height: 1.6;
  color: #303133;
  white-space: pre-wrap;
  background-color: #EBEDF2;
  border-radius: 8px;
  flex:1;
  overflow-y: auto;
}

.script-loading {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 200px;
  color: #909399;
  font-size: 14px;
}

.script-loading .el-icon {
  margin-right: 8px;
  font-size: 18px;
}

.script-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 200px;
  color: #909399;
  font-size: 14px;
  background-color: #EBEDF2;
  border-radius: 8px;
}

.storyboard-list-area {
  flex: 1;
}

.storyboard-list-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.storyboard-list-title {
  font-size: 18px;
  font-weight: 600;
  color: #303133;
}

.storyboard-cards {
  display: flex;
  flex-direction: column;
  gap: 15px;
  max-height: 70vh;
  overflow-y: auto;
}

.storyboard-card {
  border: 1px solid #e4e7ed;
  border-radius: 8px;
  padding: 15px;
  transition: all 0.3s;
}

.storyboard-card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 15px;
  padding-bottom: 10px;
}

.storyboard-card-title {
  font-size: 16px;
  font-weight: 600;
  color: #303133;
}

.form-item {
  margin-bottom: 15px;
}

.form-label {
  font-size: 14px;
  font-weight: 500;
  color: #303313;
  margin-bottom: 8px;
  display: flex;
}
.form-label-item {
  font-weight: normal;
  width: 68px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  position: relative;
}
.label-selected {
  color: #3644E0;
  font-weight: 500;
}
.label-selected::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 24px;
  height: 3px;
  background-color: #3644E0;
}

.generate-mode-container {
  padding: 16px 0;
}

.generate-mode-container .el-select {
  width: 100%;
}

.generate-mode-section {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid #f0f0f0;
}

.generate-mode-label {
  font-size: 14px;
  color: #64687A;
  margin-bottom: 8px;
  font-weight: 500;
}

.generate-mode-select {
  width: 100%;
}

.form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 15px;
  margin-bottom: 15px;
}

.actors-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.actor-item {
  background-color: #f8f9fa;
  border-radius: 4px;
  padding: 10px;
}

.scene-description {
  font-size: 14px;
  color: #606266;
  margin-bottom: 10px;
}

.scene-preview {
  margin-bottom: 10px;
}

.scene-image {
  width: 100%;
  max-height: 120px;
  object-fit: cover;
  border-radius: 4px;
}

.scene-actions {}

.scene-actions-content {
  display: flex;
  align-items: flex-end;
  gap: 15px;
}

.current-scene-preview {
  width: 100px;
  height: 100px;
  border-radius: 4px;
  overflow: hidden;
  position: relative;
}

.preview-scene-wrapper {
  margin-top: 8px;
  display: flex;
  gap: 8px;
}

.current-scene-text {
  margin-top: 4px;
  font-size: 12px;
}

.current-scene-text-tip {
  color: var(--theme-color);
  font-size: 12px;
}

.current-scene-text-desc {
  font-size: 12px;
  line-height: 20px;
  color: #525466;
}

.current-scene-image {
  width: 100px;
  height: 100px;
  object-fit: cover;
}

.scene-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background-color: #f5f7fa;
  color: #909399;
  font-size: 12px;
}

.scene-placeholder .el-icon {
  font-size: 18px;
  margin-bottom: 3px;
}

.scene-buttons {
  display: flex;
  align-items: center;
}

.divider {
  width: 1px;
  height: 14px;
  background-color: #dcdfe6;
}

/* Scene dialog styles */
:deep(.scene-dialog .el-dialog__header) {
  margin-right: 0;
  padding-bottom: 16px;
  border-bottom: 1px solid #e4e7ed;
}

:deep(.scene-dialog .el-dialog__body) {
  padding: 20px 24px;
}

:deep(.scene-dialog .el-dialog__footer) {
  padding: 16px 24px;
  border-top: 1px solid #e4e7ed;
}

.required-mark {
  color: #f56c6c;
  margin-left: 4px;
}

.upload-type-switch {
  margin-bottom: 20px;
  padding: 4px;
  border-radius: 12px;
  background: #4764960F;
}
.video-type-switch {
  margin-bottom: 16px;
  padding: 4px;
  border-radius: 12px;
  background: #4764960F;
}
:deep(.video-type-switch .el-radio-group) {
  width: 100%;
}
:deep(.video-type-switch .el-radio-button) {
  flex: 1;
  width: 100%;
}
:deep(.video-type-switch .el-radio-button__inner) {
  width: 100%;
}

.ai-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 200px;
  width: 100%;
  background-color: #f5f7fa;
  border-radius: 6px;
}

.form-actions {
  display: flex;
  justify-content: flex-end;
  margin-top: 15px;
}

/* 图集和视频区域样式 */
.gallery-area {
  min-height: 600px;
  background-color: transparent;
  width: 100%;
  border-radius: 8px;
  padding: 20px 0 20px 20px;
  flex: 2;
}

/* 视频区域样式 */
.video-area {
  width: 100%;
  display: flex;
  gap: 16px;
  padding-bottom: 12px;
}
.storyboard-area {
  width: 192px;
  border-radius: 8px;
  padding: 0 16px 12px 16px;
  background: #fff;
  height: 100%;
  overflow: scroll;
  flex-shrink: 0;
}
.storyboard-area-title {
  display: flex;
  justify-content: space-between;
  position: sticky;
  top: 0;
  z-index: 999;
  padding-top: 12px;
  background-color: #fff;
}
.storyboard-area-title-text {
  font-size: 16px;
  color: var(--theme-color);
}
.storyboard-area-title-count {
  font-size: 14px;
  color: var(--text-color-2);
}
.storyboard-area-content-item {
  margin-top: 16px;
  border: 1px solid var(--divide-color-grey-2);
  border-radius: 6px;
  background: #fff;
  padding-top: 4px;
  display: flex;
  position: relative;
  justify-content: center;
  cursor: pointer;
  overflow: hidden;
}
.storyboard-area-content-item.active {
  border-color: var(--primary-color);
}
.storyboard-area-content-item-img {
  width: 49px;
  height: 87px;
  border-radius: 2px;
  display: flex;
  justify-content: center;
  font-size: 14px;
}
.storyboard-area-content-item-footer {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 26px;
  display: flex;
  justify-content: center;
  align-items: center;
  background: var(--bg-color-3);
  color: var(--text-color-primary);
  font-size: 14px;
}

.video-display-area {
  width: calc(100% - 192px - 360px);
  height: 100%;
  background: #fff;
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  padding: 8px 8px 8px 8px;
  justify-content: space-between;
}
.video-display-area-main {
  border-radius: 6px;
  overflow: hidden;
  border: 1px solid var(--divide-color-grey-2);
  background: var(--bg-color-3);
  flex: 1;
}
.video-display-area-list {
  display: flex;
  gap: 12px; /* 设置行和列的间距为12px */
  margin-top: 12px;
  flex-wrap: nowrap;
  overflow-x: scroll;
  overflow-y: hidden;
  padding-bottom: 12px;
}
.video-display-area-img {
  width: 72px;
  border-radius: 4px;
  height: 128px;
}
.video-display-area-error-img {
  width: 72px;
  border-radius: 4px;
  height: 128px;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 12px;
  color:#525466;
  flex-direction: column;
  background: #A2A6B829;
}
.video-display-area-error-text {
  color:#3644E0;
  cursor: pointer;
}

/* 使用Element Plus的el-tooltip，无需自定义样式 */
.video-display-area-img.active {
  border: 1px solid #3644E0;
}

.video-info-area {
  width: 360px;
  padding: 12px 16px;
  background: #fff;
  flex-shrink: 0;
}


.video-content {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.video-header {
  margin-bottom: 24px;
}

.video-placeholder {
  height: 300px;
  margin-top: 20px;
  background-color: #f5f7fa;
  border: 2px dashed #dcdfe6;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.video-requirements {
  margin-top: 40px;
}

/* 图集样式 */
.gallery-item {
  position: relative;
  border: 2px solid transparent;
  border-radius: 4px;
  overflow: hidden;
  transition: all 0.3s;
  cursor: pointer;
}

.gallery-item-active {
  border-color: #3644E0;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  transform: translateY(-2px);
}

/* 添加选中标记 */
.gallery-item-active::after {
  content: "";
  position: absolute;
  top: 10px;
  right: 10px;
  width: 24px;
  height: 24px;
  background-color: #3644E0;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.gallery-item-active::before {
  content: "";
  position: absolute;
  top: 10px;
  right: 10px;
  width: 24px;
  height: 24px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white' width='18px' height='18px'%3E%3Cpath d='M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 14px;
  z-index: 1;
}

.gallery-thumbnail {
  width: 100%;
  object-fit: cover;
}

.image-actions {
  display: flex;
  justify-content: space-around;
  padding: 8px;
  background-color: #f5f7fa;
  border-top: 1px solid #e4e7ed;
}

.image-actions .el-button {
  padding: 4px 8px;
  font-size: 12px;
}

.loading-item {
  background: linear-gradient(205.92deg, #C0CEFF 1.74%, #CDF2FF 52.4%, #F8CEFF 105.69%);
  background-size: 200% 200%;
  animation: gradientMove 4s ease infinite;
  height: 180px;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
}

@keyframes gradientMove {
  0% {
    background-position: 0% 100%;
  }

  50% {
    background-position: 100% 0%;
  }

  100% {
    background-position: 0% 100%;
  }
}

.loading-item .loading-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  color: #fff;
  text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1);
  font-weight: 500;
}

.loading-item .loading-icon {
  font-size: 30px;
  animation: rotate 1.5s linear infinite;
}

@keyframes rotate {
  from {
    transform: rotate(0deg);
  }

  to {
    transform: rotate(360deg);
  }
}

.selected-image-container {
  height: 180px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border-radius: 8px;
  cursor: pointer;
  border: 1px solid #d9d9d9;
  transition: all 0.3s;
}

.selected-image-container:hover {
  border-color: #3644E0;
}

.selected-image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.selected-image-placeholder {
  color: #909399;
  font-size: 14px;
  margin-top: 24px;
}

.selected-image-placeholder .upload-icon {
  font-size: 32px;
  margin-bottom: 8px;
  color: #909399;
}

.selected-storyboard-image {
  transition: all 0.2s ease;
}

.current-storyboard-image {
  position: relative;
  border: 2px solid #3644E0;
}

.current-storyboard-image::after {
  content: "当前";
  position: absolute;
  top: 0;
  right: 0;
  background-color: #3644E0;
  color: white;
  font-size: 10px;
  padding: 2px 6px;
  border-bottom-left-radius: 6px;
}

.empty-gallery-container {
  padding: 40px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 300px;
}

/* 状态标签样式 */
.status-tag {
  display: inline-block;
  padding: 2px 6px;
  border-radius: 4px;
  font-size: 12px;
  margin-left: 8px;
}

.status-pending {
  background-color: #E8EAFC;
  color: #3644E0;
}

.status-confirmed {
  background-color: #E6F9F1;
  color: #009249;
}

.loading-container {
  padding: 40px;
  background-color: #f8f9fa;
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.polling-status {
  text-align: center;
}

.loading-icon {
  font-size: 24px;
  color: #3644E0;
  margin-bottom: 15px;
}

.loading-text {
  font-size: 16px;
  color: #606266;
  margin-bottom: 20px;
}

.polling-progress {
  width: 200px;
  height: 6px;
  background-color: #e4e7ed;
  border-radius: 3px;
  overflow: hidden;
}

.polling-bar {
  height: 100%;
  background-color: #3644E0;
  transition: width 0.3s ease;
}

.preview-image-container {
  width: 100%;
  height: 140px;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #f5f7fa;
  border-radius: 4px;
  overflow: hidden;
}

.preview-image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.preview-empty {
  width: 100%;
  height: 140px;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #f5f7fa;
  border-radius: 4px;
  color: #909399;
  font-size: 14px;
}

/* 图片预览样式 */
.image-preview-wrapper {
  position: relative;
  height: 60vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #000;
  margin-bottom: 16px;
  overflow: hidden;
}

.image-zoom-container {
  position: relative;
  height: 100%;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.2s ease;
  transform-origin: center;
}

.zoom-controls {
  position: absolute;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
  background-color: rgba(0, 0, 0, 0.5);
  padding: 8px 16px;
  border-radius: 20px;
  z-index: 10;
}

.storyboard-header-right {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  min-width: 240px;
}

.header-nav-buttons {
  display: flex;
  gap: 12px;
}

.button-group {
  display: flex;
  gap: 12px;
}

/* Scene dialog styles */
.scene-preview-wrapper {
  margin-top: 20px;
}

.scene-preview-container {
  width: 100%;
  height: 180px;
  background-color: #f5f7fa;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.scene-preview-image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.preview-title {
  font-size: 14px;
  font-weight: 500;
  color: #606266;
}

.dialog-footer {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}

.keyboard-shortcuts {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.shortcuts-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 10px;
}

.shortcuts-grid div {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.shortcuts-grid kbd {
  font-size: 16px;
  font-weight: 600;
  color: #3644E0;
  padding: 5px 10px;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  background-color: #f5f7fa;
}

.shortcuts-grid span {
  font-size: 12px;
  color: #606266;
}

.scene-image-uploader {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: border-color 0.3s;
  width: 100%;
}

.scene-image-uploader:hover {
  border-color: #3644E0;
}

.uploaded-image {
  width: 100%;
  display: block;
  object-fit: cover;
}

.upload-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 200px;
  color: #8c939d;
  background: #fff;
}

.upload-icon {
  font-size: 24px;
}

.upload-text {
  color: #525466;
  font-size: 14px;
  margin-top: 8px;
}

/* Deep selector to match Scene Management module */
:deep(.scene-image-uploader .el-upload-dragger) {
  width: 100%;
  background-color: transparent;
  border: none;
  padding: 0;
}

.ai-generate-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 20px;
  border: 2px dashed #3644E0;
  border-radius: 8px;
  transition: all 0.3s ease;
}

/* 图集样式 */
.gallery-container {
  display: flex;
  height: calc(100vh - 180px);
  gap: 12px;
}

.gallery-left-panel {
  width: 400px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
  height: 100%;
  overflow-y: scroll;
}

.gallery-right-panel {
  flex: 1;
  min-width: 0;
  height: 100%;
  background: #fff;
  padding: 16px 16px 0 16px;
  overflow-y: scroll;
}

.left-panel-header {
  display: flex;
  align-items: center;
  margin-bottom: 20px;
  justify-content: space-between;
}

.storyboard-counter {
  font-size: 14px;
  font-weight: 500;
  color: var(--theme-color, #1C1D29);
  flex: 1;
  display: flex;
  align-items: center;
}

.navigation-buttons {
  display: flex;
  gap: 12px;
}

.left-panel-card {
  background-color: #fff;
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
  padding: 16px;
  margin-bottom: 16px;
}

.card-title {
  font-size: 14px;
  color: var(--theme-color);
  margin-bottom: 12px;
  display: flex;
  justify-content: space-between;
}
.upload-btn-wrapper {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
}
.upload-btn-icon {
  width: 14px;
  height: 14px;
}
.upload-btn-text {
  color: #3644E0;
  font-size: 14px;
}

.right-panel-header {
  margin-bottom: 16px;
  display: flex;
  gap: 16px;
  align-items: center;
}
.right-panel-button {
  display: flex;
  justify-content: flex-end;
  padding-bottom: 16px;
  margin-bottom: 16px;
  border-bottom: 1px solid rgba(162, 166, 184, 0.24);
}
.right-panel-content {
  display: flex;
  justify-content: space-between;
  gap: 32px;
  margin-bottom: 16px;
}

.panel-title {
  font-size: 16px;
  font-weight: 500;
  color: #303133;
}

.storyboard-info {
  background-color: #f5f7fa;
  border-radius: 8px;
  padding: 16px;
  margin-bottom: 16px;
}

.info-item {
  margin-bottom: 12px;
}

.info-item:last-child {
  margin-bottom: 0;
}

.info-label {
  font-size: 13px;
  font-weight: 500;
  color: #606266;
  margin-bottom: 4px;
}

.info-content {
  font-size: 13px;
  color: #303133;
  line-height: 1.5;
  white-space: pre-wrap;
}

.gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 16px;
}

.selected-storyboard-images-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}

.selected-image-container {
  height: 180px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border-radius: 8px;
}

.selected-image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.selected-image-placeholder {
  color: #909399;
  font-size: 14px;
}

.gallery-item {
  position: relative;
  border: 2px solid transparent;
  border-radius: 4px;
  overflow: hidden;
  transition: all 0.3s;
  cursor: pointer;
  font-size: 0;
}

.gallery-item-active {
  border-color: #3644E0;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  transform: translateY(-2px);
}

/* 添加选中标记 */
.gallery-item-active::after {
  content: "";
  position: absolute;
  top: 10px;
  right: 10px;
  width: 24px;
  height: 24px;
  background-color: #3644E0;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.gallery-item-active::before {
  content: "";
  position: absolute;
  top: 10px;
  right: 10px;
  width: 24px;
  height: 24px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white' width='18px' height='18px'%3E%3Cpath d='M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 14px;
  z-index: 1;
}

.gallery-thumbnail {
  width: 100%;
  object-fit: cover;
}

/* 角色选择样式 */
.actor-selection {
  width: 100%;
}

.actor-selection-row {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
}

.selected-actor-text {
  font-size: 14px;
  color: #606266;
}

.actor-preview-row {
  width: 100%;
  border-radius: 4px;
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
}

.actor-images-grid {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  width: 100%;
}

.preview-image-wrapper {
  position: relative;
  width: 56px;
  height: 100px;
  display: flex;
  justify-content: center;
  align-items: center;
  border-radius: 4px;
  overflow: hidden;
}

.preview-delete-btn {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 20px;
  height: 20px;
  background-color: rgba(0, 0, 0, 0.6);
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.3s ease;
  z-index: 10;
}

.preview-delete-btn:hover {
  background-color: rgba(0, 0, 0, 0.8);
}

.preview-delete-btn .el-icon {
  color: white;
  font-size: 12px;
}

.preview-image-wrapper:hover .preview-delete-btn {
  opacity: 1;
}

.actor-preview-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 4px;
}

.actor-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  color: #909399;
  font-size: 14px;
  background-color: #f5f7fa;
}

.actor-placeholder .el-icon {
  font-size: 24px;
  margin-bottom: 8px;
}

.actor-select-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  width: 100%;
}

.header-title {
  font-size: 14px;
  color: var(--text-color-2);
}

.actor-forms-container {
  max-height: 500px;
  overflow-y: auto;
}

.actor-form-item {
  margin-bottom: 20px;
}

.actor-form-item:last-child {
  margin-bottom: 0;
}

.form-label {
  display: flex;
  align-items: center;
  font-size: 14px;
  font-weight: 500;
  color: #303133;
  margin-bottom: 8px;
}

/* 针对角色选择弹窗中的form-label特殊处理 */
.actor-form-item .form-label {
  justify-content: space-between;
}

.delete-btn-inline {
  margin-left: auto;
  padding: 0 !important;
  min-height: auto !important;
  height: auto !important;
  border: none !important;
  background: transparent !important;
}

.delete-btn-inline:hover {
  background: rgba(245, 108, 108, 0.1) !important;
}

.actor-images-preview {
  margin-top: 20px;
}

.preview-title {
  font-size: 14px;
  font-weight: 500;
  color: #606266;
  margin-bottom: 12px;
}

.actor-images-grid {
  display: flex;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
}

.actor-image-item {
  position: relative;
  border: 2px solid transparent;
  border-radius: 4px;
  overflow: hidden;
  cursor: pointer;
  transition: all 0.3s;
}

.actor-image-item.selected {
  border-color: #3644E0;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.actor-view-image {
  width: 100px;
  height: 100px;
  border-radius: 8px;
  object-fit: cover;
}

.actor-view-placeholder {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #f5f7fa;
  color: #909399;
  font-size: 14px;
}

.actor-view-label {
  padding: 6px;
  text-align: center;
  font-size: 14px;
  color: #606266;
}

.selected-view-indicator {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 24px;
  height: 24px;
  background-color: #3644E0;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
}

.check-icon {
  font-size: 16px;
}
.check-export-icon {
  font-size: 10px;
}

.gallery-list {
  flex: 1;
  overflow-y: auto;
  padding-bottom: 40px;
}

.loading-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 40px;
}

.loading-content .loading-icon {
  font-size: 32px;
  color: #3644E0;
  margin-bottom: 16px;
}

.loading-content .loading-text {
  font-size: 16px;
  color: #606266;
}

.opt-wrapper {
  flex: 1;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  border-radius: 4px;
}

.opt-wrapper:hover {
  background: rgba(162, 166, 184, 0.1);
}

.opt-icon {
  font-size: 12px;
}

.opt-text {
  color: #1C1D29;
  font-size: 12px;
}

.opt-button {
  display: flex;
  width: 32px;
  height: 32px;
  justify-content: center;
  align-items: center;
  border: 1px solid rgba(31, 35, 41, 0.08);
  cursor: pointer;
}

.opt-back-button {
  width: 16px;
  height: 16px;
}

.opt-forward-button {
  width: 16px;
  height: 16px;
  transform: rotate(180deg);
}

:deep(.el-radio-button__inner) {
  background: transparent;
  border: 0 !important;
  border-radius: 10px !important;
}
:deep(.el-radio-button .el-radio-button__inner:hover) {
  color: inherit;
  background: white;
}

:deep(.el-radio-button.is-active .el-radio-button__inner) {
  background: #fff !important;
}
.video-option-wrapper {
  display: flex;
  gap:16px;
  align-items: center;
  margin-bottom: 24px;
}
.video-option-title {
  font-size: 14px;
  color:#64687A;
  white-space: nowrap;
}
.video-button-active {
  border: 1px solid #3644E0;
  background: #E8EAFC;
  color: #3644E0 !important;
  
}
.video-button {
  flex: 1;
  height: 36px;
  display: flex;
  justify-content: center;
  align-items: center;
  background: #F7F7F7;
  color: #1F2329;
  border-radius: 8px;
  box-sizing: border-box;
  cursor: pointer;
}

/* 导出素材弹窗样式 */
.export-dialog-content {
  padding: 10px 0;
}

.export-storyboard-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  max-height: 60vh;
  overflow-y: auto;
  padding: 10px;
}

/* 覆盖导出弹窗中的分镜项样式，确保每行显示四个 */
.export-storyboard-grid .storyboard-area-content-item {
  width: auto;
  margin-top: 0;
}

/* 确保图片尺寸合适 */
.export-storyboard-grid .storyboard-area-content-item-img {
  width: 49px;
  height: 87px;
  border-radius: 2px;
}

/* 使用与storyboard-area-content-item相同的样式 */
.export-storyboard-grid .storyboard-area-content-item {
  margin-top: 16px;
  border: 1px solid var(--divide-color-grey-2, #e4e7ed);
  border-radius: 6px;
  background: #fff;
  padding-top: 4px;
  display: flex;
  position: relative;
  justify-content: center;
  cursor: pointer;
  transition: all 0.3s;
}

.export-storyboard-grid .storyboard-area-content-item.selected-export-item {
  border-color: #3644E0;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  transform: translateY(-2px);
}

.selected-export-indicator {
  position: absolute;
  top: 8px;
  right: 6px;
  width: 16px;
  height: 16px;
  background-color: #3644E0;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  z-index: 2;
}
.empty-circle {
  position: absolute;
  top: 8px;
  right: 6px;
  width: 16px;
  height: 16px;
  background-color: transparent;
  border-radius: 50%;
  border: 1px solid rgba(196, 199, 204, 1);
  box-sizing: border-box;
}
.selected-full-indicator {
  width: 16px;
  height: 16px;
  background-color: #3644E0;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  z-index: 2;
}
.empty-full-circle {
  width: 16px;
  height: 16px;
  background-color: transparent;
  border-radius: 50%;
  border: 1px solid rgba(196, 199, 204, 1);
  box-sizing: border-box;
}

.selected-selected-indicator {
  position: absolute;
  top: 0px;
  right: 0px;
  width: 20px;
  height: 20px;
  background-color: #3644E0;
  border-bottom-left-radius: 4px;
  border-top-right-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  z-index: 2;
}

.export-dialog-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.left-actions {
  display: flex;
  align-items: center;
}

.right-actions {
  display: flex;
  gap: 12px;
}
.video-info-title {
  color: var(--text-color-2);
  font-size: 14px;
  margin-bottom: 8px;
}
.video-info-text {
  color: var(--text-color-primary);
  font-size: 14px;
  margin-bottom: 8px;
}
.video-info-img {
  width: 57px;
  border-radius: 8px;
}
.gallery-list-title {
  color: var(--text-color-primary);
  font-size: 16px;
  font-weight: 500;
  margin-bottom: 16px;
}
.actor-select-content {
  margin-top:  -24px;
}

/* 编辑剧集相关样式 */
.script-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
}

.edit-episode-btn {
  font-weight: 500;
}

.edit-episode-dialog :deep(.el-dialog__header) {
  padding: 20px 24px;
  margin-right: 0;
  border-bottom: 1px solid #ebeef5;
}

.edit-episode-dialog :deep(.el-dialog__body) {
  padding: 24px 30px;
}

.edit-episode-dialog :deep(.el-dialog__title) {
  font-weight: 600;
  font-size: 18px;
}

.edit-episode-dialog :deep(.el-form-item__label) {
  font-weight: 500;
  font-size: 15px;
  padding-bottom: 6px;
}

.dialog-footer {
  display: flex;
  justify-content: flex-end;
  margin-top: 16px;
}

.dialog-footer .el-button {
  min-width: 100px;
  margin-left: 16px;
}
</style>